Парсинг массивного XML из Google Maps API происхождения и назначения - PullRequest
0 голосов
/ 01 июля 2019

Этот вопрос частично связан с Получить данные Google Maps XML, проанализировать их и ввести в ячейки Excel . В предыдущем вопросе решение состояло в том, чтобы перебирать ссылки и вводить значения для каждого. Я выяснил, что можно звонить по нескольким источникам и направлениям и получать все в XML-файле из Google Maps. Теперь это один огромный XML для вывода данных. Мне нужно вывести длительность, например 1 hour 30 mins, и расстояние, например, 103 km для каждого. Как это возможно?

Также, почему есть 25 ответов XML, когда у меня есть только 5 разных вариантов?

Вот мой VBA:

Sub GetMyValuesGoogleAPI()
    Dim URL As String
    Dim originsParam As String
    Dim destinationsParam As String
    Dim APIkey As Range, TravelMode As Range

    Dim xmlDoc As DOMDocument30

    Dim origins(0 To 4) As String
    Dim destinations(0 To 4) As String

    Dim n As Integer

    n = FreeFile()
    Open Environ$("USERPROFILE") & "\Desktop\" & "test.txt" For Output As #n

    origins(0) = "London, UK"
    origins(1) = "Manchester, UK"
    origins(2) = "Liverpool, UK"
    origins(3) = "Bristol, UK"
    origins(4) = "Bath, UK"

    destinations(0) = "Cambridge, UK"
    destinations(1) = "Leeds, UK"
    destinations(2) = "Cambridge, UK"
    destinations(3) = "Norwich, UK"
    destinations(4) = "Brighton, UK"

    Set APIkey = ThisWorkbook.Worksheets("Other Data").Range("CE1")
    Set TravelMode = ThisWorkbook.Worksheets("Other Data").Range("BY3")
    Set xmlDoc = New DOMDocument30

    originsParam = Join(origins, "|")
    destinationsParam = Join(destinations, "|")
    URL = "https://maps.googleapis.com/maps/api/distancematrix/xml?origins=" & Escape(originsParam) & "&destinations=" _
    & Escape(destinationsParam) & "&mode=" & TravelMode & "&key=" & APIkey

    With xmlDoc
        .async = False
        .Load URL
        Debug.Print .XML
        Print #n, .XML
    End With

End Sub

Функция:

Public Function Escape(ByVal param As String) As String

    Dim i As Integer, BadChars As String

    BadChars = "%<>=&!@#$^()+{[}]|\;:'"",/?"
    For i = 1 To Len(BadChars)
        param = Replace(param, Mid(BadChars, i, 1), "%" & Hex(Asc(Mid(BadChars, i, 1))))
    Next
    param = Replace(param, " ", "+")
    Escape = param

End Function

Вот вывод XML:

<?xml version="1.0"?>
<DistanceMatrixResponse>
    <status>OK</status>
    <origin_address>London, UK</origin_address>
    <origin_address>Manchester, UK</origin_address>
    <origin_address>Liverpool, UK</origin_address>
    <origin_address>Bristol, UK</origin_address>
    <origin_address>Bath, UK</origin_address>
    <destination_address>Cambridge, UK</destination_address>
    <destination_address>Leeds, UK</destination_address>
    <destination_address>Cambridge, UK</destination_address>
    <destination_address>Norwich, UK</destination_address>
    <destination_address>Brighton, UK</destination_address>
    <row>
        <element>
            <status>OK</status>
            <duration>
                <value>5420</value>
                <text>1 hour 30 mins</text>
            </duration>
            <distance>
                <value>103024</value>
                <text>103 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>13268</value>
                <text>3 hours 41 mins</text>
            </duration>
            <distance>
                <value>313516</value>
                <text>314 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>5420</value>
                <text>1 hour 30 mins</text>
            </duration>
            <distance>
                <value>103024</value>
                <text>103 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>8674</value>
                <text>2 hours 25 mins</text>
            </duration>
            <distance>
                <value>189805</value>
                <text>190 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>6696</value>
                <text>1 hour 52 mins</text>
            </duration>
            <distance>
                <value>103629</value>
                <text>104 km</text>
            </distance>
        </element>
    </row>
    <row>
        <element>
            <status>OK</status>
            <duration>
                <value>12617</value>
                <text>3 hours 30 mins</text>
            </duration>
            <distance>
                <value>301588</value>
                <text>302 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>3723</value>
                <text>1 hour 2 mins</text>
            </duration>
            <distance>
                <value>71765</value>
                <text>71.8 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>12617</value>
                <text>3 hours 30 mins</text>
            </duration>
            <distance>
                <value>301588</value>
                <text>302 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>15640</value>
                <text>4 hours 21 mins</text>
            </duration>
            <distance>
                <value>336098</value>
                <text>336 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>16712</value>
                <text>4 hours 39 mins</text>
            </duration>
            <distance>
                <value>417143</value>
                <text>417 km</text>
            </distance>
        </element>
    </row>
    <row>
        <element>
            <status>OK</status>
            <duration>
                <value>13457</value>
                <text>3 hours 44 mins</text>
            </duration>
            <distance>
                <value>312942</value>
                <text>313 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>5458</value>
                <text>1 hour 31 mins</text>
            </duration>
            <distance>
                <value>117472</value>
                <text>117 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>13457</value>
                <text>3 hours 44 mins</text>
            </duration>
            <distance>
                <value>312942</value>
                <text>313 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>17245</value>
                <text>4 hours 47 mins</text>
            </duration>
            <distance>
                <value>409544</value>
                <text>410 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>17253</value>
                <text>4 hours 48 mins</text>
            </duration>
            <distance>
                <value>437125</value>
                <text>437 km</text>
            </distance>
        </element>
    </row>
    <row>
        <element>
            <status>OK</status>
            <duration>
                <value>11371</value>
                <text>3 hours 10 mins</text>
            </duration>
            <distance>
                <value>269123</value>
                <text>269 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>12344</value>
                <text>3 hours 26 mins</text>
            </duration>
            <distance>
                <value>333320</value>
                <text>333 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>11344</value>
                <text>3 hours 9 mins</text>
            </duration>
            <distance>
                <value>272045</value>
                <text>272 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>14866</value>
                <text>4 hours 8 mins</text>
            </duration>
            <distance>
                <value>386263</value>
                <text>386 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>10533</value>
                <text>2 hours 56 mins</text>
            </duration>
            <distance>
                <value>254730</value>
                <text>255 km</text>
            </distance>
        </element>
    </row>
    <row>
        <element>
            <status>OK</status>
            <duration>
                <value>11688</value>
                <text>3 hours 15 mins</text>
            </duration>
            <distance>
                <value>264172</value>
                <text>264 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>13467</value>
                <text>3 hours 44 mins</text>
            </duration>
            <distance>
                <value>352919</value>
                <text>353 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>11662</value>
                <text>3 hours 14 mins</text>
            </duration>
            <distance>
                <value>267094</value>
                <text>267 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>15183</value>
                <text>4 hours 13 mins</text>
            </duration>
            <distance>
                <value>381312</value>
                <text>381 km</text>
            </distance>
        </element>
        <element>
            <status>OK</status>
            <duration>
                <value>10850</value>
                <text>3 hours 1 min</text>
            </duration>
            <distance>
                <value>249779</value>
                <text>250 km</text>
            </distance>
        </element>
    </row>
</DistanceMatrixResponse>

1 Ответ

1 голос
/ 01 июля 2019

Рассмотрим XSLT , язык специального назначения, предназначенный для преобразования файлов XML в конечные форматы, включая другие файлы XML, файлы HTML и даже текстовые файлы.Здесь XSLT может преобразовать вашу DistanceMatrixResult структуру в формат CSV с необходимыми заголовками и строками данных для импорта в электронную таблицу Excel.Библиотека Office, MSXML (которую вы уже используете), может запускать сценарии XSLT 1.0.

И причина, по которой вы получаете 25 элементов запросов, заключается в каждом попарном сопоставлении 5 источников и 5сайты назначения (5*5).Каждая строка является парным совпадением (т. Е. Лондон, Великобритания по всем пяти направлениям).Сопоставьте эти пары соответственно в XSLT.Кстати, не забудьте разобрать текст, вместо этого используйте значения, где длительность измеряется в секундах, а расстояние в метрах.Даже если XSLT запустит математическое преобразование в десятичные часы и десятичные километры!

XSLT (сохранить как файл .xsl, специальный файл .xml, который будет прочитан в VBA)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes" method="text"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="DistanceMatrixResponse">
    <xsl:text>origin_address,destination_address,duration,distance&#xa;</xsl:text>
      <xsl:apply-templates select="row"/>
  </xsl:template>

  <xsl:template match="row">
      <xsl:variable name="row_pos"><xsl:value-of select="position()"/></xsl:variable>

      <xsl:for-each select="element">
        <xsl:variable name="elem_pos"><xsl:value-of select="position()"/></xsl:variable>
        <xsl:variable name="quot">&quot;</xsl:variable>
        <xsl:value-of select="concat($quot, ancestor::DistanceMatrixResponse/origin_address[position() = $row_pos], $quot, ',',
                                     $quot, ancestor::DistanceMatrixResponse/destination_address[position() = $elem_pos], $quot, ',', 
                                     format-number(duration/value div 3600, '##.####'), ',', 
                                     format-number(distance/value div 100, '##.####'))"/>
        <xsl:text>&#xa;</xsl:text>
      </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Онлайн-демонстрация

VBA

Public Sub RunXSLTtoCSV()
    Dim xmlDoc As New MSXML2.DOMDocument30, xslDoc As New MSXML2.DOMDocument30
    Dim txtOutput As String, csvfile As String

    ' LOAD XML AND XSL
    xmlDoc.Load "C:\Path\To\Google\Maps\API\Response.xml"
    xmlDoc.async = False
    xslDoc.Load "C:\Path\To\XSLT\Script.xsl"
    xslDoc.async = False

    ' TRANSFORM TO TEXT
    txtOutput = xmlDoc.transformNode(xslDoc)

    ' SAVE TO CSV (TO IMPORT INTO EXCEL)
    csvfile = "C:\Path\To\CSV\File.csv"
    Open csvfile For Output As #1
        Print #1, txtOutput
    Close #1

    Set xslDoc = Nothing
    Set xmlDoc = Nothing
End Sub

Выход

CSV Output

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...