【问题标题】:XPath in Visual BasicVisual Basic 中的 XPath
【发布时间】:2015-03-27 22:25:55
【问题描述】:

我在 Visual Basic 中的“SelectSingleNode”函数遇到问题。

我有以下 XML 文件:

<sistema versao="1.02" xmlns="http://www.portalfiscal.inf.br/nfe">
<det>
<prod>
    <cProd>000085</cProd>
    <xProd>MARTELO</xProd>
    <NCM>73170090</NCM>
    <uCom>UN</uCom>
    <vUnCom>7.0000</vUnCom>
</prod>
<imposto>
    <ICMS>
        <orig>0</orig>
        <CST>500</CST>
    </ICMS>
</imposto>
</det>
</sistema>

我需要节点“cProd”内的值。在这种情况下,“000085”。

我尝试了以下代码:

    Public Sub importacao()
    Dim arquivos = CheckedListBox1.CheckedItems
    Dim total = arquivos.Count

    Dim nome_produto As String

    For i As Integer = 0 To total - 1
        Dim xml As New XmlDocument

        xml.Load(arquivos.Item(i))

        nome_produto = xml.ChildNodes(0).ChildNodes(0).ChildNodes(0).SelectSingleNode("cProd").InnerText

    Next

End Sub

在“arquivos”中是一个带有 XML 文件路径的 CheckBoxList。

返回错误“对象引用未设置为对象的实例”。因为“SelectSingleNode("cProd")”返回的是空值。

我认为我错误地放置了 XPath。有人可以帮我吗?

谢谢你,对不起我的英语。

编辑:

它起作用了,我使用了一个函数来删除命名空间(来源:http://rprateek.blogspot.com.br/2011/01/how-to-remove-xmlns-namespace-from-xml.html)。然后我可以使用以下内容:xml.ChildNodes(0).SelectSingleNode("//cProd").InnerText

还有一件事。如果文件中不存在标签“cProd”(或另一个标签),那么处理可能导致的错误的最实用方法是什么?例如,在某些文件中,不会有标签“NCM”。也许我可以用“GetElementsByTagName()”验证标签是否存在?

谢谢大家。

【问题讨论】:

  • 您的示例实际上是无效的 XML。如果&lt;det&gt;&lt;prod&gt; 的父节点,那么您最后缺少&lt;/det&gt;;如果它是一个空节点,它应该是&lt;det /&gt;。顺便说一句,SelectSingleNode 允许您指定整个 XPath,因此您不需要像以前那样做。
  • 对不起,我把 XML 放在这里的时候出现了问题。现在好啦。关于 XPath,你能告诉我一个在这种情况下如何做的例子吗?谢谢。
  • 你为什么要跳槽? xml.ChildNodes(0).SelectSingleNode("//cProd")SelectSingleNode("/det/prod/cProd") 应该都适合你。

标签: xml vb.net xpath


【解决方案1】:

如 cmets 中所述,您无需希望通过节点到达您想要的节点;你可以设置整个 XPath 来寻找你想要的节点。

不过,您的 XML 还是有一点问题:它有一个没有前缀的命名空间:

<sistema versao="1.02" xmlns="http://www.portalfiscal.inf.br/nfe">

这对 XPath 查询造成了一点影响,因为所有节点都有默认的命名空间前缀,即“看不到”,但它仍然存在。

您有三个选择:

1.- 从 XML 中删除命名空间...

<sistema versao="1.02">
<det>
<prod>
    <cProd>000085</cProd>
    <xProd>MARTELO</xProd>
    <NCM>73170090</NCM>
    <uCom>UN</uCom>
    <vUnCom>7.0000</vUnCom>
</prod>
<imposto>
    <ICMS>
        <orig>0</orig>
        <CST>500</CST>
    </ICMS>
</imposto>
</det>
</sistema>

...并使用任一

xml.ChildNodes(0).SelectSingleNode("//cProd").InnerText

xml.ChildNodes(0).SelectSingleNode("/sistema/det/prod/cProd").InnerText

2.- 指定前缀(ns 是一个例子,你可以随意命名)...

<ns:sistema versao="1.02" xmlns:ns="http://www.portalfiscal.inf.br/nfe">
<ns:det>
<ns:prod>
    <ns:cProd>000085</ns:cProd>
    <ns:xProd>MARTELO</ns:xProd>
    <ns:NCM>73170090</ns:NCM>
    <ns:uCom>UN</ns:uCom>
    <ns:vUnCom>7.0000</ns:vUnCom>
</ns:prod>
<ns:imposto>
    <ns:ICMS>
        <ns:orig>0</ns:orig>
        <ns:CST>500</ns:CST>
    </ns:ICMS>
</ns:imposto>
</ns:det>
</ns:sistema>

...使用XmlNameSpaceManager...

Dim manager as New XmlNameSpaceManager(xml.NameTable)

...并使用任一

xml.ChildNodes(0).SelectSingleNode("//ns:cProd", manager).InnerText

xml.ChildNodes(0).SelectSingleNode("/ns:sistema/ns:det/ns:prod/ns:cProd", manager).InnerText

3.- 保持 XML 不变,并使用其中一个

xml.ChildNodes(0).SelectSingleNode("//*[name()='cProd']").InnerText

或者这个小怪物

xml.ChildNodes(0).SelectSingleNode("/*[name()='sistema']/*[name()='det']/*[name()='prod']/*[name()='cProd']").InnerText

/* 让您忽略命名空间。

This questionthis one 可能会帮助您更好地理解问题。

【讨论】:

  • 非常感谢。我不得不使用第三个选项。我无法更改 XML,因为它是由第三方软件生成的,并且以文本模式打开文件,编辑第一行,关闭并继续是不切实际的。而且我必须按名称选择,因为节点会根据文件改变标签“prod”内的位置。所以,再次感谢您。
猜你喜欢
  • 1970-01-01
  • 2015-11-19
  • 2016-07-29
  • 2011-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多