1

Why Am I getting MS.Internal.Xml.Xpath.XpathSelectionIterator instead of the value of a text node on this line of code

Dim encoding As New System.Text.UTF8Encoding(True)
Dim reader As New System.IO.StreamReader(temparray(0).ToString, encoding)
Dim x As XPathDocument = New XPathDocument(reader)
reader.Close() '?
Dim nav As XPathNavigator
nav = x.CreateNavigator()
nav.Evaluate("//*[name()='mcd-Lol'][*[name()='mcd-Number' and text()='1'] and *[name()='mcd-Tamanho' and text()='2']]//*[name()='mcd-Den']/text()")

whereas in this online tester http://codebeautify.org/Xpath-Tester it works pwefectly?

The Xml only has text nodes and all with namespaces.

<?xml version="1.0" encoding="UTF-8" ?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"   xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"    xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
     xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2"
xmlns:mcd="urn:acss:ccf:facturacaoelectronica:schema:xsd:Normalizados">
<ext:UBLExtensions>
<ext:UBLExtension>
<ext:ExtensionVersionID>NormalizadosExtension:1.0</ext:ExtensionVersionID>
<ext:ExtensionContent>
<mcd:NormalizadosExtension>
<mcd:TotalCare>134.49</mcd:TotalCare>
-<mcd:Lol>
<mcd:Number>1</mcd:Number>
<mcd:Tamanho>2</mcd:Tamanho>
<mcd:Area>Z</mcd:Area>
<mcd:TotalCare>124.94</mcd:TotalCare>
-<mcd:Qual>
<mcd:Area>Z</mcd:Area>
<mcd:NumeroQual>1040192667866500</mcd:NumeroQual>
<mcd:Data>2011-11-29</mcd:Data>
-<mcd:Care>
<mcd:NumeroLinha>1</mcd:NumeroLinha>
<mcd:Den>facial</mcd:Den>
<mcd:Quant>1</mcd:Quant>
</mcd:Care>
...
</mcd:Qual>
...
</mcd:Lol>

Thanks

mehrlicht
  • 75
  • 1
  • 11
  • It would be helpful if you include a SSCCE (http://sscce.org/). This one is not self-contained or correct because your XML input is not well-formed. So we're not even able to try Xpath-Tester to see what you saw there. – LarsH Sep 06 '16 at 01:33

2 Answers2

0

Presumably Xpath-Tester gave you a string as a result, which you saw as "working perfectly" because that's what you wanted. But Xpath-Tester wasn't using XPathNavigator.Evaluate(). The latter, according to the documentation, returns "result of the expression (Boolean, number, string, or node set)." The XPath expression you passed in selects a set of text nodes (because it's blah/blah/blah/text()). So, in accordance with the documentation, Evaluate() returns a node set; and the documentation say "This maps to Boolean, Double, String, or XPathNodeIterator objects respectively." So you get an XPathNodeIterator result, to iterate over your text node set.

If you just want the string value of the (first) text node, you could wrap string() around your XPath expression:

nav.Evaluate("string(//*[name()='mcd-Lol'][*[name()='mcd-Number' and text()='1']
              and *[name()='mcd-Tamanho' and text()='2']]//*[name()='mcd-Den']/text())")

I'm not going to ask why you're using name()='mcd-Lol', with a hyphen instead of a colon, instead of using local-name()='Lol' and possibly namespace mappings. You didn't ask about it, so I guess you've got that part working.

LarsH
  • 27,481
  • 8
  • 94
  • 152
0

You can use xml linq

Imports System.IO
Imports System.Xml
Imports System.Xml.Linq
Module Module1
    Const FILENAME As String = "c:\temp\test.xml"
    Sub Main()
        Dim xml As String = File.ReadAllText(FILENAME)
        Dim doc As XDocument = XDocument.Parse(xml)
        Dim invoice As XElement = CType(doc.FirstNode, XElement)
        Dim mcdNs = invoice.GetNamespaceOfPrefix("mcd")

        Dim results As XElement  = invoice.Descendants(mcdNs + "Lol") _
                      .Where(Function(x) (CType(x.Element(mcdNs + "Number"), Integer) = 1) And _
                                         (CType(x.Element(mcdNs + "Tamanho"), Integer) = 2)) _
                      .FirstOrDefault()

    End Sub

End Module
jdweng
  • 33,250
  • 2
  • 15
  • 20