我可以使用XSLT组合多个XML文件并转换为一个CSV吗?

时间:2013-09-11 18:29:13

标签: xml xslt csv cloudmade

替代标题:如何将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处理器的语言重用该解决方案。

0 个答案:

没有答案