提取父元素位于默认命名空间中的 XML 子元素

本文关键字:元素 命名空间 XML 于默认 提取 默认 | 更新日期: 2023-09-27 18:34:03

我有下面的XML,我一直在尝试提取名字,姓氏和其他名字一段时间,现在我遇到了各种各样的问题。

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

我可以在文档下的本地监视项中看到。DocumentElement,所有 InnerXML 和 InnerText。内部XML看起来像这样...

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

提取父元素位于默认命名空间中的 XML 子元素

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

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

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

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

  • <PatientRecord>读作{cds}:PatientRecord
  • <cdsd:LegalName>读作{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 是子节点,因此您可以从它开始,也可以将.用于当前上下文节点。

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

相反,

您可以使用 Linq to XML 的 XmlDocument 类,这很容易。您需要使用 System.Xml.Linq namspace,例如:

            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">