提取父项在默认命名空间中的XML子元素

时间:2014-12-12 15:21:02

标签: c# xml xml-namespaces

我有以下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#代码提取但仍无法提取上述数据。我得到一个nullreferenceexception。

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>

3 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

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

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

我想知道您没有收到错误消息,因为cdscds_dt没有URI,而namspaces需要是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表达式的第一个字符是斜杠,则表达式相对于文档,否则相对于当前上下文节点。您在SelectSingleNode() - doc.DocumentElement元素节点上调用OmdCdsPatientRecord是一个子节点,因此您可以从它开始,或者使用.作为当前上下文节点。

答案 2 :(得分:-1)

相反,您可以使用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属性beacuse元素具有前缀“cdsd”