使用 Microsoft Xml Parser MSXML2 如何使用 XPath 检索属性值?
With Microsoft Xml Parser MSXML2 how to retrieve value of an attribute using XPath?
这是另一个关于如何获取属性值的问题。我知道在使用 Microsoft 的 MSXML2 SelectNodes 和 SelectSingleNode 方法时存在限制,因为它们必须 return 一个节点集。
我原以为在表达式末尾使用 text() 不会 return 节点集,但后来我发现了 IXMLDOMText 类型,它可以被视为 IXMLDOMAttribute 类型的子节点让我想知道是否真的可以只使用 XPath 来挖掘属性的值。
IXMLDOMText 是一个节点而不是文字,因此(理论上)它可以参与一个节点集,即一个节点集可以包含一个 IXMLDOMText。
这是一些实验代码。它在 Excel VBA 中运行,您需要设置一个 Tools->Reference
你可以在底部看到我的尝试注释掉了我的尝试。有聪明的人知道答案吗?
我希望能够在节点上调用 .xml 方法并获取属性的值,目前这样做会提供键和值对,而不仅仅是值。
版主们,请不要认为这是重复的,因为我想我已经发现了一个新的角度。
以下 SO 文章都建议将 Xpath 包装在 string() 中,但这对 MSXML2.SelectNodes 不起作用,因为它必须 return 一个节点集
Getting attribute using XPath
Extract value of attribute node via XPath
How to get attribute value from node using xpath?
Option Explicit
Sub Test()
'* Requires Tools->References-> Microsoft XML, v6.0
Dim doc As MSXML2.DOMDocument60
Set doc = New MSXML2.DOMDocument60
'* THE OBJECTIVE IS TO INVENT AN XPATH THAT RETRIEVES THE VALUE OF AN ATTRIBUTE USING SOMETHING LIKE /a/c/@id/text()
Dim s As String
s = _
"<a>" & _
"<b>1stbText" & _
"</b>" & _
"<b>2ndbText" & _
"</b>" & _
"<c id='5'>cText" & _
"</c>" & _
"</a>"
doc.LoadXML s
Debug.Assert doc.parseError = 0
TestB doc
TestA doc
TestC doc
TestCID doc
TestCIDText doc
End Sub
Sub TestB(ByVal doc As MSXML2.DOMDocument60)
Dim xmlBTextNodes As MSXML2.IXMLDOMNodeList
Set xmlBTextNodes = doc.SelectNodes("/a/b/text()")
Debug.Assert Not xmlBTextNodes Is Nothing
Debug.Assert xmlBTextNodes.Length = 2
Debug.Assert xmlBTextNodes(0).Text = "1stbText"
Debug.Assert xmlBTextNodes(1).Text = "2ndbText"
Debug.Assert TypeName(xmlBTextNodes(0)) = "IXMLDOMText"
Dim xmlCastToText As MSXML2.IXMLDOMText
Set xmlCastToText = xmlBTextNodes(0)
Debug.Assert xmlCastToText.xml = "1stbText"
Debug.Assert xmlCastToText.Text = "1stbText"
End Sub
Sub TestA(ByVal doc As MSXML2.DOMDocument60)
Dim xmlATextNodes As MSXML2.IXMLDOMNodeList
Set xmlATextNodes = doc.SelectNodes("/a/text()")
Debug.Assert Not xmlATextNodes Is Nothing
Debug.Assert xmlATextNodes.Length = 0 '* interesting
End Sub
Sub TestC(ByVal doc As MSXML2.DOMDocument60)
Dim xmlCTextNodes As MSXML2.IXMLDOMNodeList
Set xmlCTextNodes = doc.SelectNodes("/a/c/text()")
Debug.Assert Not xmlCTextNodes Is Nothing
Debug.Assert xmlCTextNodes.Length = 1
Debug.Assert xmlCTextNodes(0).xml = "cText"
Debug.Assert xmlCTextNodes(0).Text = "cText"
Dim xmlCastToText As MSXML2.IXMLDOMText
Set xmlCastToText = xmlCTextNodes(0)
Debug.Assert xmlCastToText.xml = "cText"
Debug.Assert xmlCastToText.Text = "cText"
End Sub
Sub TestCID(ByVal doc As MSXML2.DOMDocument60)
Dim xmlCIDNodes As MSXML2.IXMLDOMNodeList
Set xmlCIDNodes = doc.SelectNodes("/a/c/@id")
Debug.Assert Not xmlCIDNodes Is Nothing
Debug.Assert xmlCIDNodes.Length = 1
Debug.Assert xmlCIDNodes(0).xml = "id=""5"""
Debug.Assert xmlCIDNodes(0).Text = "5"
Debug.Assert TypeName(xmlCIDNodes(0)) = "IXMLDOMAttribute"
Debug.Assert xmlCIDNodes(0).ChildNodes.Length = 1
Dim xmlCastToText As MSXML2.IXMLDOMText
Set xmlCastToText = xmlCIDNodes(0).ChildNodes(0)
Debug.Assert xmlCastToText.xml = "5"
Debug.Assert xmlCastToText.Text = "5"
Debug.Assert xmlCastToText.ChildNodes.Length = 0
End Sub
Sub t2()
'* a convenient entry so I can press F5 and run in the same vicinity as Sub TestCIDText()
Test
End Sub
Sub TestCIDText(ByVal doc As MSXML2.DOMDocument60)
Dim xmlCIDTextNodes As MSXML2.IXMLDOMNodeList
'*** crucial XPath where I'd like to retrieve the text of an attribute
'Set xmlCIDTextNodes = doc.SelectNodes("/a/c/@id/text") '* doesn't work, returns 0 nodes
'Set xmlCIDTextNodes = doc.SelectNodes("/a/c/@id/text()") '* doesn't work, returns 0 nodes
'Set xmlCIDTextNodes = doc.SelectNodes("string(/a/c/@id)") '* doesn't work, throws "Expression must evaluate to a node-set. -->string(/a/c/@id)<--"
Debug.Assert Not xmlCIDTextNodes Is Nothing
Debug.Assert xmlCIDTextNodes.Length = 1 '<========stops here because of XPath not working
Debug.Assert xmlCIDTextNodes(0).xml = "5" '<== we can predict these results from the tail of Sub TestCID
Debug.Assert xmlCIDTextNodes(0).Text = "5"
Debug.Assert xmlCIDTextNodes(0).ChildNodes.Length = 0
End Sub
Sub Test()
'* Requires Tools->References-> Microsoft XML, v6.0
Dim doc As MSXML2.DOMDocument60
Dim nl As MSXML2.IXMLDOMNodeList
Dim s As String, n As MSXML2.IXMLDOMNode
Dim v
Set doc = New MSXML2.DOMDocument60
s = "<a>" & _
"<b>1stbText" & _
"</b>" & _
"<b>2ndbText" & _
"</b>" & _
"<c id='5'>cText" & _
"</c>" & _
"</a>"
doc.LoadXML s
'if possibly multiple matches...
Set nl = doc.SelectNodes("/a/c/@id")
For Each n In nl
Debug.Print n.NodeValue ' >> "5"
Next n
'if expecting just one match...
Set n = doc.SelectSingleNode("/a/c/@id")
If Not n Is Nothing Then Debug.Print n.NodeValue '>> "5"
'or?
Debug.Print doc.SelectSingleNode("/a/c/@id").Text
End Sub
这是另一个关于如何获取属性值的问题。我知道在使用 Microsoft 的 MSXML2 SelectNodes 和 SelectSingleNode 方法时存在限制,因为它们必须 return 一个节点集。
我原以为在表达式末尾使用 text() 不会 return 节点集,但后来我发现了 IXMLDOMText 类型,它可以被视为 IXMLDOMAttribute 类型的子节点让我想知道是否真的可以只使用 XPath 来挖掘属性的值。
IXMLDOMText 是一个节点而不是文字,因此(理论上)它可以参与一个节点集,即一个节点集可以包含一个 IXMLDOMText。
这是一些实验代码。它在 Excel VBA 中运行,您需要设置一个 Tools->Reference
你可以在底部看到我的尝试注释掉了我的尝试。有聪明的人知道答案吗?
我希望能够在节点上调用 .xml 方法并获取属性的值,目前这样做会提供键和值对,而不仅仅是值。
版主们,请不要认为这是重复的,因为我想我已经发现了一个新的角度。
以下 SO 文章都建议将 Xpath 包装在 string() 中,但这对 MSXML2.SelectNodes 不起作用,因为它必须 return 一个节点集
Getting attribute using XPath
Extract value of attribute node via XPath
How to get attribute value from node using xpath?
Option Explicit
Sub Test()
'* Requires Tools->References-> Microsoft XML, v6.0
Dim doc As MSXML2.DOMDocument60
Set doc = New MSXML2.DOMDocument60
'* THE OBJECTIVE IS TO INVENT AN XPATH THAT RETRIEVES THE VALUE OF AN ATTRIBUTE USING SOMETHING LIKE /a/c/@id/text()
Dim s As String
s = _
"<a>" & _
"<b>1stbText" & _
"</b>" & _
"<b>2ndbText" & _
"</b>" & _
"<c id='5'>cText" & _
"</c>" & _
"</a>"
doc.LoadXML s
Debug.Assert doc.parseError = 0
TestB doc
TestA doc
TestC doc
TestCID doc
TestCIDText doc
End Sub
Sub TestB(ByVal doc As MSXML2.DOMDocument60)
Dim xmlBTextNodes As MSXML2.IXMLDOMNodeList
Set xmlBTextNodes = doc.SelectNodes("/a/b/text()")
Debug.Assert Not xmlBTextNodes Is Nothing
Debug.Assert xmlBTextNodes.Length = 2
Debug.Assert xmlBTextNodes(0).Text = "1stbText"
Debug.Assert xmlBTextNodes(1).Text = "2ndbText"
Debug.Assert TypeName(xmlBTextNodes(0)) = "IXMLDOMText"
Dim xmlCastToText As MSXML2.IXMLDOMText
Set xmlCastToText = xmlBTextNodes(0)
Debug.Assert xmlCastToText.xml = "1stbText"
Debug.Assert xmlCastToText.Text = "1stbText"
End Sub
Sub TestA(ByVal doc As MSXML2.DOMDocument60)
Dim xmlATextNodes As MSXML2.IXMLDOMNodeList
Set xmlATextNodes = doc.SelectNodes("/a/text()")
Debug.Assert Not xmlATextNodes Is Nothing
Debug.Assert xmlATextNodes.Length = 0 '* interesting
End Sub
Sub TestC(ByVal doc As MSXML2.DOMDocument60)
Dim xmlCTextNodes As MSXML2.IXMLDOMNodeList
Set xmlCTextNodes = doc.SelectNodes("/a/c/text()")
Debug.Assert Not xmlCTextNodes Is Nothing
Debug.Assert xmlCTextNodes.Length = 1
Debug.Assert xmlCTextNodes(0).xml = "cText"
Debug.Assert xmlCTextNodes(0).Text = "cText"
Dim xmlCastToText As MSXML2.IXMLDOMText
Set xmlCastToText = xmlCTextNodes(0)
Debug.Assert xmlCastToText.xml = "cText"
Debug.Assert xmlCastToText.Text = "cText"
End Sub
Sub TestCID(ByVal doc As MSXML2.DOMDocument60)
Dim xmlCIDNodes As MSXML2.IXMLDOMNodeList
Set xmlCIDNodes = doc.SelectNodes("/a/c/@id")
Debug.Assert Not xmlCIDNodes Is Nothing
Debug.Assert xmlCIDNodes.Length = 1
Debug.Assert xmlCIDNodes(0).xml = "id=""5"""
Debug.Assert xmlCIDNodes(0).Text = "5"
Debug.Assert TypeName(xmlCIDNodes(0)) = "IXMLDOMAttribute"
Debug.Assert xmlCIDNodes(0).ChildNodes.Length = 1
Dim xmlCastToText As MSXML2.IXMLDOMText
Set xmlCastToText = xmlCIDNodes(0).ChildNodes(0)
Debug.Assert xmlCastToText.xml = "5"
Debug.Assert xmlCastToText.Text = "5"
Debug.Assert xmlCastToText.ChildNodes.Length = 0
End Sub
Sub t2()
'* a convenient entry so I can press F5 and run in the same vicinity as Sub TestCIDText()
Test
End Sub
Sub TestCIDText(ByVal doc As MSXML2.DOMDocument60)
Dim xmlCIDTextNodes As MSXML2.IXMLDOMNodeList
'*** crucial XPath where I'd like to retrieve the text of an attribute
'Set xmlCIDTextNodes = doc.SelectNodes("/a/c/@id/text") '* doesn't work, returns 0 nodes
'Set xmlCIDTextNodes = doc.SelectNodes("/a/c/@id/text()") '* doesn't work, returns 0 nodes
'Set xmlCIDTextNodes = doc.SelectNodes("string(/a/c/@id)") '* doesn't work, throws "Expression must evaluate to a node-set. -->string(/a/c/@id)<--"
Debug.Assert Not xmlCIDTextNodes Is Nothing
Debug.Assert xmlCIDTextNodes.Length = 1 '<========stops here because of XPath not working
Debug.Assert xmlCIDTextNodes(0).xml = "5" '<== we can predict these results from the tail of Sub TestCID
Debug.Assert xmlCIDTextNodes(0).Text = "5"
Debug.Assert xmlCIDTextNodes(0).ChildNodes.Length = 0
End Sub
Sub Test()
'* Requires Tools->References-> Microsoft XML, v6.0
Dim doc As MSXML2.DOMDocument60
Dim nl As MSXML2.IXMLDOMNodeList
Dim s As String, n As MSXML2.IXMLDOMNode
Dim v
Set doc = New MSXML2.DOMDocument60
s = "<a>" & _
"<b>1stbText" & _
"</b>" & _
"<b>2ndbText" & _
"</b>" & _
"<c id='5'>cText" & _
"</c>" & _
"</a>"
doc.LoadXML s
'if possibly multiple matches...
Set nl = doc.SelectNodes("/a/c/@id")
For Each n In nl
Debug.Print n.NodeValue ' >> "5"
Next n
'if expecting just one match...
Set n = doc.SelectSingleNode("/a/c/@id")
If Not n Is Nothing Then Debug.Print n.NodeValue '>> "5"
'or?
Debug.Print doc.SelectSingleNode("/a/c/@id").Text
End Sub