【问题标题】:Using SelectSingleNode with XPath returns NULL将 SelectSingleNode 与 XPath 一起使用会返回 NULL
【发布时间】:2013-07-17 09:59:21
【问题描述】:

我尝试使用 SelectSingleNode 修改 XML 文件。 文件结构是

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ProjectExtensions>
    <Borland.Personality>Delphi.Personality</Borland.Personality>
    <Borland.ProjectType>VCLApplication</Borland.ProjectType>
    <BorlandProject>
      <BorlandProject>
        <Delphi.Personality>
          <Parameters>
            ...
          </Parameters>
          <VersionInfo>
            <VersionInfo Name="IncludeVerInfo">True</VersionInfo>
            <VersionInfo Name="AutoIncBuild">False</VersionInfo>
            <VersionInfo Name="MajorVer">4</VersionInfo>
            <VersionInfo Name="MinorVer">1</VersionInfo>
            <VersionInfo Name="Release">3</VersionInfo>
            <VersionInfo Name="Build">559</VersionInfo>
            <VersionInfo Name="Debug">False</VersionInfo>
            <VersionInfo Name="PreRelease">False</VersionInfo>
            <VersionInfo Name="Special">False</VersionInfo>
            <VersionInfo Name="Private">False</VersionInfo>
            <VersionInfo Name="DLL">False</VersionInfo>
            <VersionInfo Name="Locale">1049</VersionInfo>
            <VersionInfo Name="CodePage">1251</VersionInfo>
          </VersionInfo>
...
...
...

我在 VS C# 上的代码是

using System.Xml;

namespace xmledit
{
    class Program
    {
        private static void Main(string[] args)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load("arm.xml");
            var node = doc.SelectSingleNode("//VersionInfo[@Name='Build']");
            if (node != null)
                node.InnerText = "123";                
            doc.Save("temp.xml");
        }
    }
}

所以,我尝试用Name="Build" 修改标签VersionInfo,但SelectSingleNode 返回NULL。 我做错了什么?

【问题讨论】:

  • 您是否介意我制作一个完全不同的解决方案,使用 LINQ -> XML 而不是 XPath?
  • 是的,会很好

标签: c# xml xpath selectsinglenode


【解决方案1】:

您的 xml 文档有一个默认命名空间 xmlns="http://schemas.microsoft.com/developer/msbuild/2003",因此(我假设)您需要使用 XmlNamespaceManager。

【讨论】:

  • 请至少看一下文档,如果您无法弄清楚,请返回。
  • 好的。我解决了这个问题。非常感谢
【解决方案2】:

此函数将向您的文档添加一个命名空间管理器。将“mysite”替换为您想要的任何内容。在此之后,您可以选择带有“mysite:[nodename]”的节点。

public static XmlNamespaceManager AttachNamespaces(ref XmlDocument xmldoc)
    {
        XmlNamespaceManager NS = default(XmlNamespaceManager);
        XmlNode rootnode = default(XmlNode);
        string strTest = null;
        string attrname = null;
        string ns = null;

        NS = new XmlNamespaceManager(xmldoc.NameTable);
        rootnode = xmldoc.DocumentElement;
        strTest = GetAttribute(ref rootnode, "xmlns");
        if (string.IsNullOrEmpty(strTest))
        {
            NS.AddNamespace("mysite", "http://www.mysite.com/");
        }
        else
        {
            NS.AddNamespace("mysite", strTest);
        }

        // Add namespaces from XML root tag
        foreach (XmlAttribute attr in rootnode.Attributes)
        {
            attrname = attr.Name;
            if (attrname.IndexOf("xmlns:") == 0 && !string.IsNullOrEmpty(attrname))
            {
                ns = attrname.Substring(7);
                NS.AddNamespace(ns, attr.Value);
            }
        }

        return NS;

}

辅助函数:

public static string GetAttribute(ref XmlNode mynode, string AttributeName, string DefaultValue = "")
    {
        XmlAttribute myattr = default(XmlAttribute);
        string rtn = "";

        if (mynode != null)
        {
            myattr = mynode.Attributes[AttributeName];
            if (myattr != null)
            {
                rtn = mynode.Attributes[AttributeName].Value;
            }
        }

        if (string.IsNullOrEmpty(rtn))
            rtn = DefaultValue;

        return rtn;
    }

例如:

XmlDocument xmldoc = new XmlDocument;
// Load something into xmldoc
XmlNamespaceManager NS = AttachNamespaces(ref XmlDocument xmldoc);
XMLNode mynode = xmldoc.SelectSingleNode("//mysite:VersionInfo[@Name='Build']", NS);

【讨论】:

  • 我没有使用命名空间,但是您的帮助函数可以很好地获取 XML 属性,所以谢谢。
【解决方案3】:

你需要定义命名空间:

看看这个答案:SelectSingleNode returning null for known good xml node path using XPath

【讨论】:

    【解决方案4】:

    @Pål Thingbø

    您在子字符串中使用了错误的位置,并且您的解决方案无法处理默认命名空间。

    我已经修改了它,所以它现在对我有用。谢谢! (尽管仍然没有处理没有命名空间的“xmlns:”标签(attrname==6)。我认为这应该会引发错误,因为它在 XML 中是不允许的。

    private static XmlNamespaceManager AttachNamespaces(XmlDocument xmldoc)
        {
            XmlNamespaceManager nsMgr = new XmlNamespaceManager(xmldoc.NameTable);
            XmlNode rootnode = xmldoc.DocumentElement;
            string strTest = GetAttribute(ref rootnode, "xmlns");
            nsMgr.AddNamespace("mysite", string.IsNullOrEmpty(strTest) ? "http://example.com/" : strTest);
    
            // Add namespaces from XML root tag
            if (rootnode.Attributes != null)
                foreach (XmlAttribute attr in rootnode.Attributes)
                {
                    string attrname = attr.Name;
                    if (attrname.IndexOf("xmlns", StringComparison.Ordinal) == 0 && !string.IsNullOrEmpty(attrname))
                    {
                        if (attrname.Length == 5) // default Namespace
                        {
                            string ns = "default";
                            nsMgr.AddNamespace(ns, attr.Value);
                        }
                        else if (attrname.Length > 6)
                        {
                            string ns = attrname.Substring(6);
                            nsMgr.AddNamespace(ns, attr.Value);
                        }
                    }
                }
    
            return nsMgr;
    
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-07
      • 2020-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-08
      • 2016-06-11
      • 2023-03-07
      相关资源
      最近更新 更多