替代标题:如何将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"
我对基本的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()>1]">
<xsl:value-of select="' '"/>
<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处理器的语言重用该解决方案。