0

替代标题:如何将 CloudMade API 响应集转换为单个 CSV 文件?

我有大约 1000 个 XML 文件,其中包含来自CloudMade API的地理编码响应。

据我所知,CloudMade 没有批处理 API,也不输出 CSV。

我想将一组 XML 文件转换为一个 CSV 文件,其中每个响应包含一行。

是否可以仅使用 XSLT 1.0 来做到这一点?如果没有,是否存在 XSLT 2.0 解决方案?

CSV 必须至少包含三列:ID、纬度和经度。

每个 XML 文件的基本名称都包含响应 ID。

第一个 Array 元素的 Latitude 和 Longitude 元素包含纬度和经度值。

小例子

这是一个只有两个 XML 文件的小示例。

文件140.xml如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <places>
    <Array pos="0">
      <addressType>housenumber</addressType>
      <city>~Weiz</city>
      <country>Austria</country>
      <featureType>Ortsstrasse</featureType>
      <houseNumber>19</houseNumber>
      <position>
        <lat>47.22148736</lat>
        <lon>15.62440613</lon>
      </position>
      <street>Dr.-Karl-Widdmann-Straße</street>
      <zip>8160</zip>
    </Array>
  </places>
  <status>
    <duration>205</duration>
    <procedure>geo.location.search.2</procedure>
    <success>true</success>
  </status>
</Response>

文件141.xml如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <places>
    <Array pos="0">
      <addressType>housenumber</addressType>
      <city>~Innsbruck</city>
      <country>Austria</country>
      <featureType>Ortsstrasse</featureType>
      <houseNumber>50</houseNumber>
      <position>
        <lat>47.26638083</lat>
        <lon>11.43725792</lon>
      </position>
      <street>Valiergasse</street>
      <zip>6020</zip>
    </Array>
  </places>
  <status>
    <duration>139</duration>
    <procedure>geo.location.search.2</procedure>
    <success>true</success>
  </status>
</Response>

输出cloudmade_responses.csv应以 UTF-8 编码,应如下所示:

"Id","Latitude","Longitude"
"140","47.22148736","15.62440613"
"141","47.26638083","11.43725792"

部分 XSLT 解决方案

我对基本的 XPath 很满意,但不确定如何将 XPath 表达式集成到更复杂的 XSLT 文档中。

提取纬度的 XPath 表达式是

/Response/places/Array[@pos=0]/position/lat

提取经度的 XPath 表达式是

/Response/places/Array[@pos=0]/position/lon

将这些传递给XmlStar以将单个文档转换为不带引号的 CSV 行:

$ xml sel -t -v "/Response/places/Array[@pos=0]/position/lat" -o "," -v "/Response/places/Array[@pos=0]/position/lon" 140.xml
47.22148736,15.62440613

添加-C选项并对输出进行管道传输会写入转换的 XSLT 描述:

xml select -C -t -v "/Response/places/Array[@pos=0]/position/lat" -o "," -v "/Response/places/Array[@pos=0]/position/lon" 140.xml > partial_solution.xslt

输出partial_solution.xslt如下所示:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
  <xsl:output omit-xml-declaration="yes" indent="no"/>
  <xsl:template match="/">
    <xsl:call-template name="value-of-template">
      <xsl:with-param name="select" select="/Response/places/Array[@pos=0]/position/lat"/>
    </xsl:call-template>
    <xsl:text>,</xsl:text>
    <xsl:call-template name="value-of-template">
      <xsl:with-param name="select" select="/Response/places/Array[@pos=0]/position/lon"/>
    </xsl:call-template>
  </xsl:template>
  <xsl:template name="value-of-template">
    <xsl:param name="select"/>
    <xsl:value-of select="$select"/>
    <xsl:for-each select="exslt:node-set($select)[position()&gt;1]">
      <xsl:value-of select="'&#10;'"/>
      <xsl:value-of select="."/>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

我现在可以使用 XSLT 文件执行相同的转换:

$ xml tr partial_solution.xslt 140.xml
47.22148736,15.62440613

但是,我不确定如何修改 XSLT 描述以满足我的所有要求。

老实说,我也不能说我完全理解部分 XSLT 解决方案。

使用脚本语言的完整解决方案

PowerShell 是一种脚本语言,内置支持 XML 和 CSV 处理。凭借其简洁的管道语法,您可以用几行代码解决问题:

Get-ChildItem -Path |
Select -Property @(
  @{ Name = 'Id'; Expression = { $_.BaseName } },
  @{ Name = 'Latitude'; Expression = {(Select-Xml -Path $_.FullName -XPath '/Response/places/Array[@pos=0]/position/lat').Node.InnerText } },
  @{ Name = 'Longitude'; Expression = {(Select-Xml -Path $_.FullName -XPath '/Response/places/Array[@pos=0]/position/lon').Node.InnerText } }
) |
Export-Csv -Path '.\cloudmade_responses.csv' -NoTypeInformation -Encoding UTF8

在与 XML 文件相同的目录中执行该操作会生成一个名为cloudmade_response.csv. 它看起来像这样:

"Id","Latitude","Longitude"
"140","47.22148736","15.62440613"
"141","47.26638083","11.43725792"

输出与指定的完全相同。

在 Python 和 Perl 等其他脚本语言中肯定也有类似的简洁解决方案。

使用 XSLT 解决问题应该允许任何具有 XSLT 处理器的语言重用该解决方案。

4

0 回答 0