C# 使用XmlDocument从具有或不具有命名空间的xml文件中读取

C# 使用XmlDocument从具有或不具有命名空间的xml文件中读取,c#,xml,namespaces,C#,Xml,Namespaces,我有一些代码使用XmlDocument从具有名称空间的xml文件读取。我的挑战是,我现在读取的文件名称空间是硬编码的,我将其传递给XmlNamespaceManager。我希望我的方法更加灵活。从任何类型的xml文件读取。如果它具有名称空间,然后使用名称空间管理器读取元素,而无需对名称空间进行硬编码。如果文件没有名称空间,则继续分析它。下面是我所做的 xmldoc = new XmlDocument (); xmldoc.Load (fileLocation); XmlNamespaceMa

我有一些代码使用XmlDocument从具有名称空间的xml文件读取。我的挑战是,我现在读取的文件名称空间是硬编码的,我将其传递给XmlNamespaceManager。我希望我的方法更加灵活。从任何类型的xml文件读取。如果它具有名称空间,然后使用名称空间管理器读取元素,而无需对名称空间进行硬编码。如果文件没有名称空间,则继续分析它。下面是我所做的

xmldoc = new XmlDocument ();
xmldoc.Load (fileLocation);


XmlNamespaceManager nameSpaceManager = new XmlNamespaceManager(xmldoc.NameTable);

nameSpaceManager.AddNamespace ("ns","http://schemas.sample.data.org/2005");

XmlNodeList nodeList = xmldoc.SelectNodes("/ns:Demo/ns:Items",  nameSpaceManager);
if (nodeList != null) 
{
    foreach (XmlNode childNode in nodeList) 
    {
        string first = childNode.SelectSingleNode ("ns:First", nameSpaceManager).InnerText;
        string second= childNode.SelectSingleNode ("ns:Second", nameSpaceManager).InnerText;
        string third = childNode.SelectSingleNode ("ns:Third", nameSpaceManager).InnerText;
    }
}
下面是我正在使用的示例xml文件

<Demo xmlns:i="http://www.justasample.com" xmlns="http://schemas.sample.data.org/2005">
 <Items>

  <First>first</First>
  <Second>second</Second>
  <Third>third</Third>

  </Items>

</Demo>

第一
第二
第三
使用Linq to XML和my,特别是内部处理的,您可以执行以下操作:

XElement root = XElement.Load(fileLocation);
var items = root.Descendants("Items")
                .Select(item => new
                {
                    First = item.Get("First", ""),
                    Second= item.Get("Second", ""),
                    Third = item.Get("Third", "")
                });

<> p> >每个<代码>第一< /代码>,<代码>第二版>代码> <代码>第三> /代码>元素将使用<代码>项目> /COD>元素的命名空间,以确定其自己的命名空间。

您可以考虑以下选项:

  • 确定文档是否包含命名空间,并根据它构造xpath查询
  • 使用与命名空间无关的xpath,例如
    local-name()
    ,这将 忽略名称空间
  • 选项1

    var xmlDoc = new XmlDocument();
    xmlDoc.Load(fileLocation);
    //determine  whether document contains namespace
    var namespaceName = "ns";
    var namespacePrefix = string.Empty;
    XmlNamespaceManager nameSpaceManager = null;
    if (xmlDoc.FirstChild.Attributes != null)
    {
        var xmlns = xmlDoc.FirstChild.Attributes["xmlns"];
        if (xmlns != null)
        {
              nameSpaceManager = new XmlNamespaceManager(xmlDoc.NameTable);
              nameSpaceManager.AddNamespace(namespaceName, xmlns.Value);
              namespacePrefix = namespaceName + ":";
        }
    }
    
    XmlNodeList nodeList = xmlDoc.SelectNodes(string.Format("/{0}Demo/{0}Items",namespacePrefix), nameSpaceManager);
    if (nodeList != null)
    {
        foreach (XmlNode childNode in nodeList)
        {
           string first = childNode.SelectSingleNode(namespacePrefix + "First", nameSpaceManager).InnerText;
           string second = childNode.SelectSingleNode(namespacePrefix + "Second", nameSpaceManager).InnerText;
           string third = childNode.SelectSingleNode(namespacePrefix +  "Third", nameSpaceManager).InnerText;
         }
     }
    
    选项2

    XmlNodeList nodeList = xmlDoc.SelectNodes("/*[local-name() = 'Demo']/*[local-name() = 'Items']");
    if (nodeList != null)
    {
        foreach (XmlNode childNode in nodeList)
        {    
            string first = childNode.SelectSingleNode("*[local-name() = 'First']").InnerText;
            string second = childNode.SelectSingleNode("*[local-name() = 'Second']").InnerText;
            string third = childNode.SelectSingleNode("*[local-name() = 'Third']").InnerText;
         }
    }
    

    改进Vadim的选项1,但使用XDocument(而不是XmlDocument)API和F#而不是C#:

    让fileStream=File.Open(fileLocation,FileMode.Open)
    让xDocument=xDocument.LoadFileStream
    让我们选择=
    让nsString=xDocument.Root.Name.Namespace.ToString()
    如果String.IsNullOrEmpty nsString,则
    Console.Error.WriteLine“警告:在xmlns attrib中找不到命名空间URL”
    没有一个
    其他的
    让nsManager=XmlNamespaceManager(NameTable())
    设nsPrefix=“x”
    nsManager.AddNamespace(nsPrefix,nsString)
    如果是“字符串”http://schemas.sample.data.org/2005”“那么
    Console.Error.WriteLine“警告:命名空间URL与预期不匹配,查询可能导致没有元素”
    一些(nsManager,sprintf“%s:”nsPrefix)
    let query=“//{0}演示/{0}项”
    让节点=
    将nsOpt与
    |无->
    设fixedQuery=String.Format(查询,String.Empty)
    xDocument.XPathSelectElements fixedQuery
    |一些(nsManager、nsPrefix)->
    设fixedQuery=String.Format(查询,nsPrefix)
    xDocument.XPathSelectElements(fixedQuery,nsManager)
    对于节点中的节点,请执行以下操作:
    ...
    
    您可以在xml文件中提供
    所有名称空间
    ,并动态添加它们

    var document = new XmlDocument();
    document.LoadXml(rawData);
    
    var nsmgr = new XmlNamespaceManager(document.NameTable);
    nsmgr.AddNamespace("dpx", document.DocumentElement.NamespaceURI); //default
    
    var attributeCollection = document.DocumentElement.Attributes;
    for (int i = 0; i < attributeCollection.Count; i++)
    {
        var isAttribute = nsmgr.LookupNamespace(attributeCollection[i].LocalName) == null;     
        if (isAttribute)
            nsmgr.AddNamespace(attributeCollection[i].LocalName, attributeCollection[i].Value);
    }
    
    XmlElement xmlElem = document.DocumentElement;
    var node = xmlElem.SelectSingleNode(xpath, nsmgr);
    
    var document=new XmlDocument();
    LoadXml(rawData);
    var nsmgr=新的XmlNamespaceManager(document.NameTable);
    nsmgr.AddNamespace(“dpx”,document.DocumentElement.NamespaceURI)//违约
    var attributeCollection=document.DocumentElement.Attributes;
    for(int i=0;i

    如果XML中的节点没有
    前缀
    ,则在提供路径时,应为它们提供
    默认前缀

    不使用XDocument的原因是什么?这使得一切,特别是名称空间,变得容易多了。好吧,它不是真正的复制品。但是,请更清楚地说明什么对您当前的方法有效,什么对您当前的方法无效。@HenkHolterman,它实际上不必只是XmlDocument。我愿意接受任何其他建议。我想我把它放在问题中,因为这是我实现的。为了澄清我的问题,我目前的方法没有那么好用,因为名称空间是硬编码的。我需要摆脱它,使它能够与任何xml文件一起工作。非常感谢你的回答。我正在马上实现它,并会让你知道它是如何工作的。我尝试了这两个选项,它们工作得很好。非常感谢你。我接受了这个答案因为它很简单并且解释得很好。关于实现选项2,有一个简单的问题,在我们处理名称空间时,有没有办法忽略节点“Demo”呢?假设“Demo”是自动生成的,并且不是常量..下次它将有另一个唯一的名称。但是内部节点将始终称为“Items”。是否可以忽略实现中的“Demo”但仍然解析文件?当然,xpath
    /*[local-name()='Items']
    会起作用,例如:
    XmlNodeList nodeList=xmlDoc.SelectNodes(“/*[local-name()='Items']”)我还实现了最后一个部分,它可以正常工作。这就是我现在拥有的:xmlDoc.SelectNodes(“//*[local-name()='Items']”);选项2很好,这样,你可以用多个名称空间解析它,效果很好。@Chuck Savage谢谢你的回复。我很感激。
    
    var document = new XmlDocument();
    document.LoadXml(rawData);
    
    var nsmgr = new XmlNamespaceManager(document.NameTable);
    nsmgr.AddNamespace("dpx", document.DocumentElement.NamespaceURI); //default
    
    var attributeCollection = document.DocumentElement.Attributes;
    for (int i = 0; i < attributeCollection.Count; i++)
    {
        var isAttribute = nsmgr.LookupNamespace(attributeCollection[i].LocalName) == null;     
        if (isAttribute)
            nsmgr.AddNamespace(attributeCollection[i].LocalName, attributeCollection[i].Value);
    }
    
    XmlElement xmlElem = document.DocumentElement;
    var node = xmlElem.SelectSingleNode(xpath, nsmgr);