【问题标题】:Select single XML node from document从文档中选择单个 XML 节点
【发布时间】:2020-04-01 11:43:16
【问题描述】:

我正在尝试从 Philips Hue Bridge 返回的 XML 文档中加载一些值。这是我尝试解析的 XML 示例(来自 Philips 网站的示例):

<root xmlns="urn:schemas-upnp-org:device-1-0">
    <specVersion>
        <major>1</major>
        <minor>0</minor>
    </specVersion>
    <URLBase>https://192.168.1.130:80/</URLBase>
    <device>
        <deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>
        <friendlyName>Philips hue (192.168.1.130)</friendlyName>
        <manufacturer>Royal Philips Electronics</manufacturer><manufacturerURL>https://www.philips.com</manufacturerURL>
        <modelDescription>Philips hue Personal Wireless Lighting</modelDescription>
        <modelName>Philips hue bridge 2012</modelName>
        <modelNumber>929000226503</modelNumber>
        <modelURL>https://www.meethue.com</modelURL>
        <serialNumber>001788102201</serialNumber>
        <UDN>uuid:2f402f80-da50-11e1-9b23-001788102201</UDN>
        <presentationURL>index.html</presentationURL>
        <iconList>
            <icon>
                <mimetype>image/png</mimetype>
                <height>48</height>
                <width>48</width>
                <depth>24</depth>
                <url>hue_logo_0.png</url>
            </icon>
            <icon>
                <mimetype>image/png</mimetype>
                <height>120</height>
                <width>120</width>
                <depth>24</depth>
                <url>hue_logo_3.png</url>
            </icon>
        </iconList>
    </device>
</root>

我在网上查看了几个示例并尝试了各种路径,但结果始终为空。我在 cmets 中放了多个示例,向您展示我尝试过的一些事情。

var xml = webClient.DownloadString($"http://{bridge.internalipaddress.ToString()}/description.xml");
XmlDocument bridgeDetails = new XmlDocument();
bridgeDetails.LoadXml(xml);
XmlNode root = bridgeDetails.DocumentElement;
var friendlyName = bridgeDetails.SelectSingleNode("//device/friendlyName");
//var friendlyName = bridgeDetails.SelectSingleNode("/device/friendlyName");
//var friendlyName = bridgeDetails.SelectSingleNode("device/friendlyName");
//var friendlyName = bridgeDetails.SelectSingleNode("descendant::device/friendlyName");
//var friendlyName = root.SelectSingleNode("//device/friendlyName");
//var friendlyName = root.SelectSingleNode("/device/friendlyName");
//var friendlyName = root.SelectSingleNode("device/friendlyName");
//var friendlyName = root.SelectSingleNode("descendant::device/friendlyName");
//I've also tried adding .Value.ToString() at the end of some of these, but that just caused a null reference exception

编辑:

我发现我缺少命名空间。但我不确定如何,因为没有指向名称空间的 URL。例如

var nsmgr = new XmlNamespaceManager(bridgeDetails.NameTable);
nsmgr.AddNamespace("upnp", "urn:schemas-upnp-org:device-1-0");

XmlNode root = bridgeDetails.DocumentElement;
var friendlyName = bridgeDetails.SelectSingleNode("//upnp:device/friendlyName");

任何帮助将不胜感激。

【问题讨论】:

  • 您的 XML 位于由 xmlns="urn:schemas-upnp-org:device-1-0" 在根元素上创建的命名空间中。您必须在 XPath 表达式中尊重这一点,否则它将返回 null。因此,请阅读 C# 中的命名空间以及如何在 XPath 表达式中使用它们。
  • 谢谢,我刚刚解决了这个问题,但不知道该怎么做。请查看我的编辑。

标签: c# xpath xml-parsing


【解决方案1】:

添加命名空间后您的解决方案很接近。
现在使用以下 XPath-1.0 表达式,因为 所有 子级或 &lt;root&gt; 都在此命名空间中:

//upnp:device/upnp:friendlyName

完整的应该是这样的

var friendlyName = bridgeDetails.SelectSingleNode("//upnp:device/upnp:friendlyName", nsmgr);

并返回值

飞利浦色相 (192.168.1.130)


关于你的陈述

但我不确定如何,因为没有指向命名空间的 URL。

命名空间 URI 不必是有效的 URL。它只需要是一个唯一的字符串(在您的 "name"-space 中)并且它不必指向可检索的文件。这不是必须的。

【讨论】:

  • 谢谢你的工作,虽然我不完全理解为什么每个元素名称之前都需要upnp:。我知道它们都在该命名空间内,但是当您指的是您已经指定的子元素在该命名空间中时(即upnp:device),为什么仍然需要它?
  • 命名空间在其定义后被所有子代继承。如果在其中一个孩子上定义了一个新的默认命名空间,那么这个命名空间将从那里继承。
猜你喜欢
  • 1970-01-01
  • 2012-04-10
  • 2017-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多