【问题标题】:Extracting XML Child Elements Where the Parents are in a Defaulted Namespace提取父元素位于默认命名空间中的 XML 子元素
【发布时间】:2015-02-11 08:16:54
【问题描述】:

我有下面的 XML,我一直在尝试提取 FirstName、LastName 和 OtherName 一段时间,现在我遇到了各种各样的问题。

<OmdCds xmlns="cds"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:cdsd="cds_dt"
        xsi:schemaLocation="cds ontariomd_cds.xsd">   
  <PatientRecord>
    <Demographics>
      <Names>
        <cdsd:LegalName namePurpose="L">
          <cdsd:FirstName>
            <cdsd:Part>SARAH</cdsd:Part>
            <cdsd:PartType>GIV</cdsd:PartType>
            <cdsd:PartQualifier>BR</cdsd:PartQualifier>
          </cdsd:FirstName>
          <cdsd:LastName>
            <cdsd:Part>GOMEZ</cdsd:Part>
            <cdsd:PartType>FAMC</cdsd:PartType>
            <cdsd:PartQualifier>BR</cdsd:PartQualifier>
          </cdsd:LastName>
          <cdsd:OtherName>
            <cdsd:Part>GABRIELA</cdsd:Part>
            <cdsd:PartType>GIV</cdsd:PartType>
            <cdsd:PartQualifier>BR</PartQualifier>   

我目前尝试使用以下 c# 代码进行提取,但仍无法提取上述数据。我得到一个空引用异常。

XmlDocument doc = new XmlDocument();
doc.Load(folder + "\\" + o.ToString());
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(doc.NameTable);
namespaceManager.AddNamespace("cdsd", "http://www.w3.org/2001/XMLSchema-instance");
XmlNode firstName = doc.DocumentElement.SelectSingleNode("/PatientRecord/Demographics/Names/cdsd:LegalName/cdsd:FirstName/cdsd:Part", namespaceManager);
string fName = firstName.InnerText;
MessageBox.Show(fName);

我可以在 doc.DocumentElement 下的本地监视项中看到所有 InnerXML 和 InnerText。 InnerXML 看起来像这样...

  <PatientRecord xmlns=\"cds\"><Demographics><Names><cdsd:LegalName namePurpose=\"L\" xmlns:cdsd=\"cds_dt\"><cdsd:FirstName><cdsd:Part>SARAH</cdsd:Part><cdsd:PartType>GIV</cdsd:PartType><cdsd:PartQualifier>BR</cdsd:PartQualifier></cdsd:FirstName>

【问题讨论】:

  • 使用 XmlDocument 吗?使用 LINQ to XML 通常可以更简单地处理命名空间。此外,如果您以后可以多注意格式化您的代码和愉快地采样 XML,它会更容易为您提供帮助。
  • 你可以试试没有命名空间的xpath吗? XmlNode firstName = doc.DocumentElement.SelectSingleNode("/PatientRecord/Demographics/Names/LegalName/FirstName/Part");
  • 这里的许多答案都错过了他们的 xPath 的一个关键字符。 xPath 像这样开始“./cds:PatientRecord/ - 错过了让我发疯的时期,直到我阅读并意识到时期(.)丢失了。

标签: c# xml xml-namespaces


【解决方案1】:

您在文档中有 3 个命名空间定义:

  • cds - 作为默认命名空间
  • http://www.w3.org/2001/XMLSchema-instance- 带有 xsi 前缀
  • cds_dt - 带有 cdsd 前缀

我想知道您没有收到错误消息,因为 cdscds_dt 不是 URI,而命名空间必须是 URI。

如果您尝试理解元素名称,则需要将前缀替换为实际的命名空间。

  • &lt;PatientRecord&gt; 读作 {cds}:PatientRecord
  • &lt;cdsd:LegalName&gt; 读作 {cds_dt}:LegalName

现在在 XPath 1.0 中,注册命名空间也会发生同样的情况。但是 XPath 没有默认命名空间。因此,没有一个元素不会使用默认命名空间进行扩展。

您需要在命名空间管理器上注册命名空间前缀。前缀不需要和文档中的一样。

namespaceManager.AddNamespace("cdsd", "cds_dt");
namespaceManager.AddNamespace("cds", "cds");

现在您可以在 XPath 中使用已注册的命名空间了:

doc.DocumentElement.SelectSingleNode(
  "cds:PatientRecord/cds:Demographics/cds:Names/cdsd:LegalName/cdsd:FirstName/cdsd:Part",
  namespaceManager
);

如果 XPath 表达式的第一个字符是斜线,则表达式相对于文档,否则相对于当前上下文节点。您在 doc.DocumentElement - OmdCds 元素节点上调用 SelectSingleNode()PatientRecord 是一个子节点,因此您可以从它开始,也可以将. 用于当前上下文节点。

【讨论】:

  • 只需要在 XPath 的开头添加句点。例如:“./cds:PatientRecord/cds.....”
  • 其实你可以把/去掉。我更新了答案并添加了解释。
【解决方案2】:

PatientRecordDemographicsNames 位于 cds 命名空间中。这是因为 OmdCds 元素 (xmlns="cds") 上的默认命名空间声明。其他的位于cdsd 命名空间中,而不是xsi。您必须添加它们并在 XPATH 中使用它们:

namespaceManager.AddNamespace("cdsd", "cdsd");
namespaceManager.AddNamespace("cds", "cds");
XmlNode firstName = doc.DocumentElement.SelectSingleNode(
    "/cds:PatientRecord/cds:Demographics/cds:Names/cdsd:LegalName/cdsd:FirstName/cdsd:Part",
    namespaceManager);

顺便说一句,您得到NullReferenceException 是因为您错误地假设您的查询将始终返回一个节点。您现在看到了当它不返回节点时会发生什么。只要查询可能没有返回值,请始终检查null

【讨论】:

    【解决方案3】:

    您可以使用 Linq to XML 代替 XmlDocument 类,很容易。您需要使用 System.Xml.Linq 命名空间,例如:

                XDocument xdoc = XDocument.Load("path");
                IEnumerable<XElement> nodes = (from p in xdoc.Descendants()
                                               where p.Name.LocalName == "FirstName"
                                               select p).Elements();
    
                foreach (XElement nodeFirstName in nodes)
                {
                    foreach (XElement parts in nodeFirstName.Elements())
                    {
                      string strExtracted = parts.Name.LocalName + " " + parts.Value;
                    }
                }
    

    使用 LocalName 属性是因为元素具有前缀“cdsd”

    【讨论】:

    • 你应该学会使用命名空间而不是使用本地名称。
    • 约翰,你知道我不知道如何使用它?我正在对这个问题做出快速可行的回应。请注意。
    • 他 prestado atención。 Usted le dio ninguna indicación de que usted sabe cómo usarlos。 Si usted sabe cómo usarlos, muestran en su respuesta。顺便说一句,aqui se habla Inglés。
    • 我是 StackOverflow 的新评论,我对这个论坛的看法是它应该帮助人们解决任何问题并提供解决方案,而不是假装自己是宇宙的主人。这就是我亲爱的朋友。
    • 我在这个网站上的时间比你长一点。而且,顺便说一句,这不是一个论坛。
    猜你喜欢
    • 2013-12-04
    • 1970-01-01
    • 2018-05-21
    • 1970-01-01
    • 2021-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多