Using SelectSingleNode with XPath returns NULL

房东的猫 提交于 2019-12-11 01:05:24

问题


I trying to modify an XML file with SelectSingleNode. The structure of file is

<?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>
...
...
...

My code on VS C# is

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");
        }
    }
}

So, i trying to modify Tag VersionInfo with Name="Build", but SelectSingleNode returns NULL. What I doing wrong?


回答1:


Your xml document has an default namespace xmlns="http://schemas.microsoft.com/developer/msbuild/2003" therefore (I assume) you need to use a XmlNamespaceManager.

  • http://msdn.microsoft.com/en-us/library/h0hw012b.aspx
  • http://msdn.microsoft.com/en-us/library/d6730bwt.aspx



回答2:


This function will add a namespacemanager to your document. Replace "mysite" with whatever you want. After this, you can select nodes with "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;

}

Helper function:

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;
    }

For instance:

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



回答3:


You need to define the namespace:

Have a look at this answer: SelectSingleNode returning null for known good xml node path using XPath




回答4:


@Pål Thingbø

You're using the wrong position in your Substring and your solution does not handle a default namespace.

I have modified it, so it works for me now. Thank you! (Although there is still no handling for a "xmlns:" tag without a namespace (attrname==6). I think this should raise an error, because it's not allowed in 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;

    }


来源:https://stackoverflow.com/questions/17696745/using-selectsinglenode-with-xpath-returns-null

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!