Используя VBA, как загрузить набор данных API в Excel из функции HTTP GET? - PullRequest
1 голос
/ 10 апреля 2019

Я пытаюсь загрузить выходные данные DataSet из вызова API непосредственно в диапазон ячеек на моем листе.В частности, мне просто нужны TASK_ID, TASK_NUMBER, TASK_RESUME и TASK_GROUP_NAME.Они предоставили некоторые .NET примеры кода для функции API, которую я использую, но код не переводится непосредственно в VBA.

Я успешно проанализировал и использовал JSONдля предыдущих функций, но для этой задачи мне нужно вывести ответ обратно в Excel.У меня есть возможность форматировать HTTP-ответ как XML, RecordSet, DataSet или JSON.Поскольку для меня это тоже небольшая возможность для обучения, я бы хотел изучить и использовать DataSet для этой функции, но если XML имеет больше смысла, я буду доверять вашему мнению, но в идеале я бы хотел использовать его.либо.

Я закомментировал соответствующий код .NET, скопированный из примера API, верхняя часть - то, что я нашел из учебника по XML.

Private URL As String
Sub Query_Click()
Dim ws As Worksheet: Set ws = Worksheets("Generator")

URL = Worksheets("API").Range("B7")
Dim strResp As String: strResp = GetHTTP(ByVal URL)
Dim xmlDoc As New MSXML2.DOMDocument
If Not xmlDoc.LoadXML(strResp) Then
    MsgBox "Load Error"
End If

'    Dim dsOutput As DataSet: dsOutput = Deserialize(Of DataSet)(strXML)
'            If dsOutput IsNot Nothing AndAlso dsOutput.Tables.Count > 0 Then
'                If dsOutput.Tables.Contains("dtAPIErrors") Then
'                    Throw New Exception(String.Format("{0}: {1}", _
'                                                      dsOutput.Tables(0).Rows(0).Item("ErrorNumber").ToString, _
'                                                      dsOutput.Tables(0).Rows(0).Item("ErrorDescription").ToString))
'                End If
'            End If

    Set xmlDoc = Nothing

End Sub
Private Function GetHTTP(ByVal URL As String) As String
    On Error Resume Next
    With CreateObject("WinHttp.WinHttpRequest.5.1")
        .Open "GET", URL, False
        .Send
        GetHTTP = .ResponseText
    End With

End Function

'Private Function Deserialize(Of T)( ByVal strXML As String) As T
'        Dim objet As T = Nothing
'        Dim objType As Type = GetType(T)
'        Try
'            If Not String.IsNullOrEmpty(strXML) Then
'                Dim objSerializer As New System.Xml.Serialization.XmlSerializer(objType)
'                Dim objText As New System.Text.StringBuilder()
'                Dim objXmlReader As New System.IO.StringReader(strXML)
'                objet = DirectCast(objSerializer.Deserialize(objXmlReader), T)
'                objXmlReader.Close()
'            End If
'            Return objet
'        Catch ex As Exception
'            Throw
'        Finally
'            If objet IsNot Nothing Then objet = Nothing
'        End Try
'End Function

Мне бы хотелосьзагрузить все, начиная с строки 9, с идентификатором задачи в столбце A, задачей № в столбце B, резюме задачи (имя задачи AKA) в столбце C и группой задач в столбец D. Если я смогу получить рабочий пример только дляЯ уверен, что смогу скопировать одну из записей DataSet для остальных.

<DataSet>
<xs:schema xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="dsOutput">
<xs:element name="dsOutput" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="dtOutput" msdata:CaseSensitive="False" msdata:Locale="en-US">
<xs:complexType>
<xs:sequence>
<xs:element name="TASK_ID" type="xs:int" minOccurs="0"/>
<xs:element name="TASK_NUMBER" type="xs:decimal" minOccurs="0"/>
<xs:element name="TASK_RESUME" type="xs:string" minOccurs="0"/>
<xs:element name="DATE_TASK_MODIFIED" msdata:DateTimeMode="Unspecified" type="xs:dateTime" minOccurs="0"/>
<xs:element name="IS_ASSIGNED_OR_REVIEWER" type="xs:int" minOccurs="0"/>
<xs:element name="ASSIGNED" type="xs:string" minOccurs="0"/>
<xs:element name="REVIEWER" type="xs:string" minOccurs="0"/>
<xs:element name="ASSIGNED_ID" type="xs:string" minOccurs="0"/>
<xs:element name="REVIEWER_ID" type="xs:string" minOccurs="0"/>
<xs:element name="PROJECT_ID" type="xs:int" minOccurs="0"/>
<xs:element name="PROJECT_NUMBER" type="xs:string" minOccurs="0"/>
<xs:element name="PROJECT_NAME" type="xs:string" minOccurs="0"/>
<xs:element name="PROJECT_TYPE_NAME" type="xs:string" minOccurs="0"/>
<xs:element name="COMPANY_ID" type="xs:int" minOccurs="0"/>
<xs:element name="TASK_GROUP_ID" type="xs:int" minOccurs="0"/>
<xs:element name="TASK_GROUP_NAME" type="xs:string" minOccurs="0"/>
<xs:element name="TASK_GROUP_MYORDER" type="xs:decimal" minOccurs="0"/>
<xs:element name="TASK_TYPE_ID" type="xs:int" minOccurs="0"/>
<xs:element name="TASK_TYPE_NAME" type="xs:string" minOccurs="0"/>
<xs:element name="TASK_TYPE_MYORDER" type="xs:decimal" minOccurs="0"/>
<xs:element name="TASK_STATUS_ID" type="xs:int" minOccurs="0"/>
<xs:element name="TASK_STATUS_NAME" type="xs:string" minOccurs="0"/>
<xs:element name="TASK_STATUS_MYORDER" type="xs:decimal" minOccurs="0"/>
<xs:element name="TASK_STATUS_COMPLETED" type="xs:unsignedByte" minOccurs="0"/>
<xs:element name="TASK_STATUS_COMPLETED_LOGICAL_SORT" type="xs:int" minOccurs="0"/>
<xs:element name="TASK_PRIORITY_ID" type="xs:int" minOccurs="0"/>
<xs:element name="TASK_PRIORITY_NAME" type="xs:string" minOccurs="0"/>
<xs:element name="TASK_PRIORITY_MYORDER" type="xs:decimal" minOccurs="0"/>
<xs:element name="USER_CREATOR_ID" type="xs:int" minOccurs="0"/>
<xs:element name="USERNAME" type="xs:string" minOccurs="0"/>
<xs:element name="FIRST_NAME" type="xs:string" minOccurs="0"/>
<xs:element name="LAST_NAME" type="xs:string" minOccurs="0"/>
<xs:element name="TASK_DESC_CREATOR" type="xs:string" minOccurs="0"/>
<xs:element name="TASK_DESC_CREATOR_PLAIN" type="xs:int" minOccurs="0"/>
<xs:element name="ESTIMATED_TIME" type="xs:decimal" minOccurs="0"/>
<xs:element name="DATE_EXPECTED_START_TASK" msdata:DateTimeMode="Unspecified" type="xs:dateTime" minOccurs="0"/>
<xs:element name="DATE_EXPECTED_END_TASK" msdata:DateTimeMode="Unspecified" type="xs:dateTime" minOccurs="0"/>
<xs:element name="DATE_TASK_CREATED" msdata:DateTimeMode="Unspecified" type="xs:dateTime" minOccurs="0"/>
<xs:element name="POURCENTAGE_DONE" type="xs:decimal" minOccurs="0"/>
<xs:element name="ACTUAL_HOURS" type="xs:int" minOccurs="0"/>
<xs:element name="ACTUAL_PERCENT_DONE" type="xs:int" minOccurs="0"/>
<xs:element name="DOCUMENT_COUNT" type="xs:decimal" minOccurs="0"/>
<xs:element name="ACTUAL_START_DATE" msdata:DateTimeMode="Unspecified" type="xs:dateTime" minOccurs="0"/>
<xs:element name="ACTUAL_END_DATE" msdata:DateTimeMode="Unspecified" type="xs:dateTime" minOccurs="0"/>
<xs:element name="DIVIDE_HOURS" type="xs:boolean" minOccurs="0"/>
<xs:element name="WEEKEND_ALLOWED" type="xs:int" minOccurs="0"/>
<xs:element name="UPDATE_USER_ID" type="xs:int" minOccurs="0"/>
<xs:element name="UPDATE_USERNAME" type="xs:string" minOccurs="0"/>
<xs:element name="UPDATE_FIRST_NAME" type="xs:string" minOccurs="0"/>
<xs:element name="UPDATE_LAST_NAME" type="xs:string" minOccurs="0"/>
<xs:element name="COUNT_SUCCESSORS" type="xs:decimal" minOccurs="0"/>
<xs:element name="COUNT_PREDECESSORS" type="xs:decimal" minOccurs="0"/>
<xs:element name="TASK_RECUR_MODIFIED" type="xs:boolean" minOccurs="0"/>
<xs:element name="TIMESHEET_INOUT_ID" type="xs:int" minOccurs="0"/>
<xs:element name="COMMENT_COUNT" type="xs:decimal" minOccurs="0"/>
<xs:element name="DATE_STATUS_STARTED" msdata:DateTimeMode="Unspecified" type="xs:dateTime" minOccurs="0"/>
<xs:element name="DATE_STATUS_COMPLETED" msdata:DateTimeMode="Unspecified" type="xs:dateTime" minOccurs="0"/>
<xs:element name="POSITION" type="xs:double" minOccurs="0"/>
<xs:element name="TASK_DEPENDENCY_ID" type="xs:int" minOccurs="0"/>
<xs:element name="MARKED" type="xs:int" minOccurs="0"/>
<xs:element name="READY_TO_START" type="xs:int" minOccurs="0"/>
<xs:element name="TASK_RECURRENCY_ID" type="xs:int" minOccurs="0"/>
<xs:element name="EXPIRATION_DATE" type="xs:int" minOccurs="0"/>
<xs:element name="STANDBY" type="xs:int" minOccurs="0"/>
<xs:element name="WEEKEND_ALLOWED_NAME" type="xs:string" minOccurs="0"/>
<xs:element name="NAV_TASK_POSITION" type="xs:int" minOccurs="0"/>
<xs:element name="PERIODICITY_SUMMARY" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<dsOutput>
<dtOutput diffgr:id="dtOutput1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
<TASK_ID>5</TASK_ID>
<TASK_NUMBER>1.0000000</TASK_NUMBER>
<TASK_RESUME>Wolf</TASK_RESUME>
<DATE_TASK_MODIFIED>2019-03-29T15:56:29.937</DATE_TASK_MODIFIED>
<IS_ASSIGNED_OR_REVIEWER>0</IS_ASSIGNED_OR_REVIEWER>
<PROJECT_ID>2</PROJECT_ID>
<PROJECT_NUMBER>0000002</PROJECT_NUMBER>
<PROJECT_NAME>Canines</PROJECT_NAME>
<PROJECT_TYPE_NAME>General</PROJECT_TYPE_NAME>
<COMPANY_ID>1</COMPANY_ID>
<TASK_GROUP_ID>4</TASK_GROUP_ID>
<TASK_GROUP_NAME>Development</TASK_GROUP_NAME>
<TASK_GROUP_MYORDER>9999999</TASK_GROUP_MYORDER>
<TASK_TYPE_ID>6</TASK_TYPE_ID>
<TASK_TYPE_NAME>Addition</TASK_TYPE_NAME>
<TASK_TYPE_MYORDER>9999999</TASK_TYPE_MYORDER>
<TASK_STATUS_ID>5</TASK_STATUS_ID>
<TASK_STATUS_NAME>Completed</TASK_STATUS_NAME>
<TASK_STATUS_MYORDER>9999999</TASK_STATUS_MYORDER>
<TASK_STATUS_COMPLETED>1</TASK_STATUS_COMPLETED>
<TASK_STATUS_COMPLETED_LOGICAL_SORT>2</TASK_STATUS_COMPLETED_LOGICAL_SORT>
<TASK_PRIORITY_ID>7</TASK_PRIORITY_ID>
<TASK_PRIORITY_NAME>Normal</TASK_PRIORITY_NAME>
<TASK_PRIORITY_MYORDER>3</TASK_PRIORITY_MYORDER>
<USER_CREATOR_ID>1</USER_CREATOR_ID>
<USERNAME>Dracius</USERNAME>
<FIRST_NAME>Ace</FIRST_NAME>
<LAST_NAME>Rimmer</LAST_NAME>
<TASK_DESC_CREATOR/>
<ESTIMATED_TIME>0.00</ESTIMATED_TIME>
<DATE_EXPECTED_START_TASK>2019-03-29T00:00:00</DATE_EXPECTED_START_TASK>
<DATE_EXPECTED_END_TASK>2019-03-29T00:00:00</DATE_EXPECTED_END_TASK>
<DATE_TASK_CREATED>2019-03-29T13:24:31.82</DATE_TASK_CREATED>
<POURCENTAGE_DONE>10</POURCENTAGE_DONE>
<DOCUMENT_COUNT>0</DOCUMENT_COUNT>
<ACTUAL_START_DATE>2019-03-29T00:00:00</ACTUAL_START_DATE>
<ACTUAL_END_DATE>2019-03-29T00:00:00</ACTUAL_END_DATE>
<DIVIDE_HOURS>true</DIVIDE_HOURS>
<WEEKEND_ALLOWED>0</WEEKEND_ALLOWED>
<UPDATE_USER_ID>3</UPDATE_USER_ID>
<UPDATE_USERNAME>Fenrir</UPDATE_USERNAME>
<COUNT_SUCCESSORS>1</COUNT_SUCCESSORS>
<COUNT_PREDECESSORS>0</COUNT_PREDECESSORS>
<TASK_RECUR_MODIFIED>false</TASK_RECUR_MODIFIED>
<COMMENT_COUNT>0</COMMENT_COUNT>
<DATE_STATUS_STARTED>2019-03-29T19:55:24.24</DATE_STATUS_STARTED>
<DATE_STATUS_COMPLETED>2019-03-29T19:55:24.24</DATE_STATUS_COMPLETED>
<POSITION>325056</POSITION>
<MARKED>0</MARKED>
<READY_TO_START>0</READY_TO_START>
<WEEKEND_ALLOWED_NAME>No</WEEKEND_ALLOWED_NAME>
</dtOutput>
<dtOutput diffgr:id="dtOutput2" msdata:rowOrder="1" diffgr:hasChanges="inserted">...</dtOutput>
<dtOutput diffgr:id="dtOutput3" msdata:rowOrder="2" diffgr:hasChanges="inserted">...</dtOutput>
<dtOutput diffgr:id="dtOutput4" msdata:rowOrder="3" diffgr:hasChanges="inserted">...</dtOutput>
<dtOutput diffgr:id="dtOutput5" msdata:rowOrder="4" diffgr:hasChanges="inserted">...</dtOutput>
<dtOutput diffgr:id="dtOutput6" msdata:rowOrder="5" diffgr:hasChanges="inserted">...</dtOutput>
<dtOutput diffgr:id="dtOutput7" msdata:rowOrder="6" diffgr:hasChanges="inserted">...</dtOutput>
<dtOutput diffgr:id="dtOutput8" msdata:rowOrder="7" diffgr:hasChanges="inserted">...</dtOutput>
<dtOutput diffgr:id="dtOutput9" msdata:rowOrder="8" diffgr:hasChanges="inserted">...</dtOutput>
</dsOutput>
</diffgr:diffgram>
</DataSet>

Пример вывода ошибок:

<DataSet>
<xs:schema xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="dsOutput">
<xs:element name="dsOutput" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="dtAPIErrors">
<xs:complexType>
<xs:sequence>
<xs:element name="ErrorNumber" type="xs:string" minOccurs="0"/>
<xs:element name="ErrorDescription" type="xs:string" minOccurs="0"/>
<xs:element name="ErrorType" type="xs:string" minOccurs="0"/>
<xs:element name="Language" type="xs:string" minOccurs="0"/>
<xs:element name="ParamName" type="xs:string" minOccurs="0"/>
<xs:element name="Id" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<dsOutput>
<dtAPIErrors diffgr:id="dtAPIErrors1" msdata:rowOrder="0">
<ErrorNumber>API0011-009</ErrorNumber>
<ErrorDescription>
Task doesn't exist. It might have been deleted by another user.
</ErrorDescription>
<ErrorType>MSG_FUNCTIONAL</ErrorType>
<Language>en-US</Language>
</dtAPIErrors>
</dsOutput>
</diffgr:diffgram>
</DataSet>

1 Ответ

1 голос
/ 10 апреля 2019

Вы можете рассматривать это как xml и использовать xpath. Здесь я читаю из файла, но вы загружаете ответ в xmldocument. Это действительно, чтобы показать, что вы можете выбрать по xpath. Я выбираю с помощью SelectSingleNode, но вы можете видеть, как можно добавить цикл для SelectNodes.

Это выровняет строку только в том случае, если наборы узлов из каждого xpath имеют одинаковую длину. Если нет, необходимо использовать общий родительский узел, а затем доступ к дочерним узлам. Счетчик строк будет увеличиваться в цикле по общему родительскому узлу.

Если используется несколько запросов, для запросов потребуется еще один цикл For Loop, а затем в верхней части этого цикла должна быть найдена следующая свободная строка, чтобы определить, с чего начать запись.

Option Explicit
Public Sub test()
    Dim xmlDoc As Object, ws As Worksheet
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    Set xmlDoc = CreateObject("MSXML2.DOMDocument")
    With xmlDoc
        .validateOnParse = True
        .setProperty "SelectionLanguage", "XPath"
        .async = False

        If Not .Load("C:\Users\User\Desktop\Test.xml") Then
            Err.Raise .parseError.ErrorCode, , .parseError.reason
        End If
    End With
    Dim node As Object, i As Long, xpath As Variant, j As Long
    j = 1
    For Each xpath In Array("TASK_ID", "TASK_NUMBER", "TASK_RESUME", "TASK_GROUP_NAME")
        ws.Cells(9, j) = xmlDoc.SelectSingleNode("//" & xpath).Text
        j = j + 1
    Next
End Sub

В вашем случае загрузите функцию, возвращающую строку. Редактировать: обновлено для нескольких узлов

Option Explicit
Public Sub test()
    Dim xmlDoc As Object, ws As Worksheet
    Set ws = ThisWorkbook.Worksheets("Sheet1")
    Set xmlDoc = CreateObject("MSXML2.DOMDocument")
    With xmlDoc
        .validateOnParse = True
        .setProperty "SelectionLanguage", "XPath"
        .async = False

        If Not .LoadXML(GetHTTP(url)) Then
            Err.Raise .parseError.ErrorCode, , .parseError.reason
        End If
    End With
    Dim node As Object, i As Long, xpath As Variant, j As Long, errorNode As Object, k As Long
    Set errorNode = xmlDoc.SelectSingleNode("//ErrorDescription")
    If Not errorNode Is Nothing Then
        MsgBox errorNode.Text
        Exit Sub
    End If
    j = 1
    For Each xpath In Array("TASK_ID", "TASK_NUMBER", "TASK_RESUME", "TASK_GROUP_NAME")
        k = 0
        For Each node In xmlDoc.SelectNodes("//" & xpath)
            ws.Cells(9 + k, j) = node.Text
            k = k + 1
        Next
        j = j + 1
    Next
End Sub
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...