I'm trying to parse an XML response from the Sharepoint REST API using Excel VBA. This is an extract of the XML code. I changed some values for confidentiality reasons
<?xml version="1.0" encoding="utf-8"?>
<feed xml:base="https://company/sites/subsite/_api/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
<id>4db71c92-9576-4c59-bb85-89d27459139e
</id>
<title />
<updated>2022-04-13T20:17:19Z
</updated>
<entry>
<id>https://company.sharepoint.com/sites/subsite/_api/Web/Lists(guid'e32e86fd-3161-4e44-a654-2424b357d566')/Items(1590)/RoleAssignments/GetByPrincipalId(3)
</id>
<category term="SP.RoleAssignment" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" href="Web/Lists(guid'e32e86fd-3161-4e44-a654-2424b357d566')/Items(1590)/RoleAssignments/GetByPrincipalId(3)" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Member" type="application/atom xml;type=entry" title="Member" href="Web/Lists(guid'e32e86fd-3161-4e44-a654-2424b357d566')/Items(1590)/RoleAssignments/GetByPrincipalId(3)/Member">
<m:inline>
<entry>
<id>https://lionbridge.sharepoint.com/sites/LIOXSalesOpsFinancialsDEV/_api/Web/Lists(guid'e32e86fd-3161-4e44-a654-2424b357d566')/Items(1590)/RoleAssignments/GetByPrincipalId(3)/Member
</id>
<category term="SP.Group" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" href="Web/Lists(guid'e32e86fd-3161-4e44-a654-2424b357d566')/Items(1590)/RoleAssignments/GetByPrincipalId(3)/Member" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Owner" type="application/atom xml;type=entry" title="Owner" href="Web/Lists(guid'e32e86fd-3161-4e44-a654-2424b357d566')/Items(1590)/RoleAssignments/GetByPrincipalId(3)/Member/Owner" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Users" type="application/atom xml;type=feed" title="Users" href="Web/Lists(guid'e32e86fd-3161-4e44-a654-2424b357d566')/Items(1590)/RoleAssignments/GetByPrincipalId(3)/Member/Users" />
<title />
<updated>2022-04-13T20:17:19Z
</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:Id m:type="Edm.Int32">3
</d:Id>
<d:IsHiddenInUI m:type="Edm.Boolean">false
</d:IsHiddenInUI>
<d:LoginName>John Smith
</d:LoginName>
<d:Title>John Smith
</d:Title>
<d:PrincipalType m:type="Edm.Int32">8
</d:PrincipalType>
<d:AllowMembersEditMembership m:type="Edm.Boolean">false
</d:AllowMembersEditMembership>
<d:AllowRequestToJoinLeave m:type="Edm.Boolean">false
</d:AllowRequestToJoinLeave>
<d:AutoAcceptRequestToJoinLeave m:type="Edm.Boolean">false
</d:AutoAcceptRequestToJoinLeave>
<d:Description m:null="true" />
<d:OnlyAllowMembersViewMembership m:type="Edm.Boolean">false
</d:OnlyAllowMembersViewMembership>
<d:OwnerTitle>John Smith
</d:OwnerTitle>
<d:RequestToJoinLeaveEmailSetting>
</d:RequestToJoinLeaveEmailSetting>
</m:properties>
</content>
</entry>
</m:inline>
</link>
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/RoleDefinitionBindings" type="application/atom xml;type=feed" title="RoleDefinitionBindings" href="Web/Lists(guid'e32e86fd-3161-4e44-a654-2424b357d566')/Items(1590)/RoleAssignments/GetByPrincipalId(3)/RoleDefinitionBindings">
<m:inline>
<feed>
<id>db3f92c8-3b3e-40eb-99de-00be4a313e5c
</id>
<title />
<updated>2022-04-13T20:17:19Z
</updated>
<entry>
<id>https://company.sharepoint.com/sites/subsite/_api/Web/RoleDefinitions(1073741829)
</id>
<category term="SP.RoleDefinition" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" href="Web/RoleDefinitions(1073741829)" />
<title />
<updated>2022-04-13T20:17:19Z
</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:BasePermissions m:type="SP.BasePermissions">
<d:High m:type="Edm.Int64">2147483647
</d:High>
<d:Low m:type="Edm.Int64">4294967295
</d:Low>
</d:BasePermissions>
<d:Description>Has full control.
</d:Description>
<d:Hidden m:type="Edm.Boolean">false
</d:Hidden>
<d:Id m:type="Edm.Int32">1073741829
</d:Id>
<d:Name>Full Control
</d:Name>
<d:Order m:type="Edm.Int32">1
</d:Order>
<d:RoleTypeKind m:type="Edm.Int32">5
</d:RoleTypeKind>
</m:properties>
</content>
</entry>
</feed>
</m:inline>
</link>
<title />
<updated>2022-04-13T20:17:19Z
</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:PrincipalId m:type="Edm.Int32">3
</d:PrincipalId>
</m:properties>
</content>
</entry>
<entry>
...
I would like to fetch the ID and LoginName (in that example, John Smith)
The VBA code I use is as follows:
'Declare variables
Dim xml_obj As MSXML2.XMLHTTP60
'Create a reference to the Microsoft XML library
Set xml_obj = New MSXML2.XMLHTTP60
'Define URL Components
base_url = "https://lionbridge.sharepoint.com/sites/lioxsalesopsfinancialsDEV/_api/web"
endpoint = "/GetFolderByServerRelativeUrl('/sites/lioxsalesopsfinancialsDEV/Shared Documents/LGS/Forecast')/ListItemAllFields/RoleAssignments?"
param_1 = "$expand="
param_1_val = "Member,RoleDefinitionBindings"
'Combine all the different components into a single URL
api_url = base_url endpoint _
param_1 param_1_val
Debug.Print api_url
'Open a new request, specify the method and the URL
xml_obj.Open bstrMethod:="GET", bstrURL:=api_url
'Send the request
xml_obj.send
'Print the status code, it should be "OK"
Debug.Print "The Request was " xml_obj.statusText
'To parse the info that is sent back, we will store it in a "document" which will leverage a document object model.
'This model has
Dim xDoc As MSXML2.DOMDocument60
Dim xNodes As MSXML2.IXMLDOMNodeList
Dim xNode As MSXML2.IXMLDOMNode
'First create a new document.
Set xDoc = New MSXML2.DOMDocument60
'Laod the response text into our document.
xDoc.LoadXML (xml_obj.responseText)
xDoc.SetProperty "SelectionNamespaces", "xmlns:d='http://schemas.microsoft.com/ado/2007/08/dataservices' xmlns:m='http://schemas.microsoft.com/ado/2007/08/dataservices/metadata'"
Set xNodes = xDoc.getElementsByTagName("m:properties")
For Each xNode In xNodes
If xNode.ChildNodes.Length <> 1 Then
Debug.Print xNode.SelectSingleNode("d:Id").Text, xNode.SelectSingleNode("d:Title").Text
End If
Next
If I use the getElementsByTagName method, I get pretty much what I need but I also get nodes that I don't want
I'd like to use the following method instead:
Set xNodes = xDoc.SelectNodes("/feed/entry/link[2]/m:inline/entry/content/m:properties")
However, xNodes.Length returns 0
What am I missing?
CodePudding user response:
In the root feed
element there are a few namespaces declared:
<feed xml:base="https://company/sites/subsite/_api/"
xmlns="http://www.w3.org/2005/Atom"
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xmlns:georss="http://www.georss.org/georss"
xmlns:gml="http://www.opengis.net/gml">
Note one of those does not have an alias - that means it's the default namespace. To query nodes using the default, you still need to add it using SetProperty "SelectionNamespaces"
, and give it an alias (I used "xxx" below) so you can use it in your xpath query:
Sub tester()
Dim xDoc As MSXML2.DOMDocument60
Dim xNodes As MSXML2.IXMLDOMNodeList
Dim xNode As MSXML2.IXMLDOMNode
Set xDoc = New MSXML2.DOMDocument60
xDoc.validateOnParse = True
xDoc.Load "C:\Temp\tmp.xml" 'loading from a file for testing
xDoc.SetProperty "SelectionNamespaces", _
"xmlns:xxx='http://www.w3.org/2005/Atom' " & _
"xmlns:d='http://schemas.microsoft.com/ado/2007/08/dataservices' " & _
"xmlns:m='http://schemas.microsoft.com/ado/2007/08/dataservices/metadata'"
Set xNodes = xDoc.SelectNodes("/xxx:feed/xxx:entry/xxx:link[2]/m:inline/xxx:entry/xxx:content/m:properties")
Debug.Print xNodes.Length '1 for my sample XML
End Sub