使用Webservice中的XSLT将XML转换为CSV

时间:2013-06-03 22:35:13

标签: web-services c#-4.0 xslt csv xmldocument

我已经搜索过这个问题,但找不到可以帮我解决问题的答案。

我正在尝试使用XSLT将XML文件转换为不同的文件格式,例如,我正在尝试将XML转换为KML和CSV。

我有一个Web服务(IIS8中的.NET 4.0),它返回一个XmlDocument。如果我将我的XML转换为KML并返回它,它运行良好并且不会返回任何错误,它会返回一个在Google地球上运行良好的有效KML文件。

但是如果我尝试将XML转换为CSV文件,我会收到以下错误:

  

根级别的数据无效。第1行,第40位。

我一直在寻找解决这个问题的方法,但没有运气。

我正在转换的XML如下:

<experience xmlns="http://www.w3schools.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://start.isel.pt:5004/schemas/xsd/experience.xsd">
<data>
<timestamp>2013-05-27 19:37:57</timestamp>
<provider origin="gps">
  <latitude>38.757893</latitude>
  <longitude>-9.275355</longitude>
  <altitude>231.1</altitude>
  <bearing>261.5</bearing>
  <speed>1.5811388</speed>
</provider>
</data>
<data>
<timestamp>2013-05-27 19:38:00</timestamp>
<provider origin="gps">
  <latitude>38.757923</latitude>
  <longitude>-9.275422</longitude>
  <altitude>251.0</altitude>
  <bearing>290.1</bearing>
  <speed>1.4142135</speed>
</provider>
</data>
<data>
<timestamp>2013-05-27 19:38:27</timestamp>
<provider origin="gps">
  <latitude>38.758038</latitude>
  <longitude>-9.275657</longitude>
  <altitude>243.4</altitude>
  <bearing>320.7</bearing>
  <speed>1.0</speed>
</provider>
</data>
<data>
<timestamp>2013-05-27 19:38:30</timestamp>
<provider origin="gps">
  <latitude>38.758007</latitude>
  <longitude>-9.275769</longitude>
  <altitude>240.9</altitude>
  <bearing>301.7</bearing>
  <speed>0.75</speed>
</provider>
</data>
</experience>

我正在使用的XSLT如下: XML&gt; KML

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xs="http://www.w3schools.com" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="utf-8"/>
<xsl:template match="/">
    <kml>
    <Document>
        <xsl:for-each select="xs:experience/xs:data/xs:provider">
            <Placemark>
                <name><xsl:value-of select="../xs:timestamp"/></name>
                <description>
                        <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
                        <b>Altitude: </b><xsl:value-of select="xs:altitude"/> m
                        <b>Bearing: </b><xsl:value-of select="xs:bearing"/> o
                        <b>Speed: </b><xsl:value-of select="xs:speed"/> km/h
                        <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
                </description>
                <Point>
                    <coordinates><xsl:value-of select="xs:longitude"/>,<xsl:value-of select="xs:latitude"/>,<xsl:value-of select="xs:altitude"/></coordinates>
                </Point>
            </Placemark>
        </xsl:for-each>
    </Document>
</kml>
</xsl:template>
</xsl:stylesheet>

如果您在以下网站XSLT Transformation Online(用于转换)Display KML Online(用于显示)中尝试上述两项内容,则一切正常。

XML&gt; CSV

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xs="http://www.w3schools.com" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="yes" encoding="utf-8"/>
<xsl:template match="/">
    <csv>timestamp,origin,reading0,reading1,reading2,reading3,reading4<xsl:text>&#xA;</xsl:text>
    <xsl:for-each select="xs:experience/xs:data">
        <xsl:value-of select="./xs:timestamp"/>,<xsl:choose>
            <xsl:when test="./xs:sensor"><xsl:value-of select="./xs:sensor/@origin"/>,<xsl:for-each select="./xs:sensor/*"><xsl:value-of select="."/>,</xsl:for-each><xsl:text>&#xA;</xsl:text></xsl:when>
            <xsl:otherwise><xsl:value-of select="./xs:provider/@origin"/>,<xsl:for-each select="./xs:provider/*"><xsl:value-of select="."/>,</xsl:for-each><xsl:text>&#xA;</xsl:text></xsl:otherwise>
        </xsl:choose>
    </xsl:for-each>
    </csv>
</xsl:template>
</xsl:stylesheet>

上面显示在网站XSLT Transformation Online中的XML的XSLT运行良好,但是使用以下C#代码给出了我在帖子开始时谈到的错误。

  

根级别的数据无效。第1行,第40位。

我在这里遗漏了什么吗?我想我是,但我找不到。

C#代码

public static String ApplyXslt2Xml(String inputXml, String inputXslt)
{
    if (inputXml == null || inputXslt == null) return null;

    XslCompiledTransform transform = new XslCompiledTransform();
    using (XmlReader reader = XmlReader.Create(new StringReader(inputXslt)))
    {
            transform.Load(reader);
    }

    StringWriter results = new StringWriter();
        using (XmlReader reader = XmlReader.Create(new StringReader(inputXml)))
    {
            transform.Transform(reader, null, results);
    }

    return results.ToString();
}

很抱歉所有这些代码,但我想尽可能多地解释我所面临的情况,因为我现在试图解决这个问题已有好几天了。

非常感谢我提出任何有用的建议。

2 个答案:

答案 0 :(得分:0)

您的csv输出中每行显示一个额外的逗号。您需要添加一个测试,以便不在提供者中为{-1}}添加此额外逗号。

<xsl:if test="not(position()=last())">,</xsl:if>

您可能还需要考虑将其分解为多个模板而不是每个循环,因为您可以更好地重用代码。

答案 1 :(得分:0)

由于你的意见:

XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(csvString);

问题似乎是,您尝试将cvs文本字符串作为XML数据加载。 你的xslt似乎是在XML元素<cvs>中创建cvs-string的缩进。

<csv>timestamp,origin,reading0,reading1,reading2,reading3,reading4<xsl:text>&#xA;</xsl:text>

<cvs> - 标记未出现在输出中,因为输出方法为text

因此你有:
将“cvsstring”作为字符串处理,将作为XML处理 或者将输出方法更改为:

<xsl:output method="xml" indent="yes" encoding="utf-8"/>

如何处理<cvs> - 标记取决于解决方案的其余部分。