1

この問題を検索しましたが、問題の解決に役立つ回答が見つかりませんでした。

XSLT を使用して XML ファイルを別のファイル形式に変換しようとしています。たとえば、XML を KML と CSV に変換しようとしています。

XmlDocument を返す Web サービス (IIS8 の .NET 4.0) があります。XML を KML に変換して返すと、問題なく動作し、エラーは返されません。たとえば、Google Earth で問題なく動作する有効な 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 > 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 (表示用)の Web サイトで上記の 2 つを試してみると、すべてうまくいきます。

XML > 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>

Web サイト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();
}

このすべてのコードで申し訳ありませんが、数日間この問題を解決しようとしているので、直面している状況についてできる限り説明したかったのです。

私が得ることができる有益な提案を前もって感謝します。

4

2 に答える 2

0

すべての行の csv 出力に余分なコンマが表示されます。<xsl:if test="not(position()=last())">,</xsl:if>プロバイダーの for-each 内のように、最後にこの余分なコンマを追加しないようにテストを追加する必要があります。

<?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:if test="not(position()=last())">,</xsl:if></xsl:for-each><xsl:text>&#xA;</xsl:text></xsl:otherwise>
        </xsl:choose>
    </xsl:for-each>
    </csv>
</xsl:template>
</xsl:stylesheet>

コードをより適切に再利用できるように、これを for each ループではなく複数のテンプレートに分割することを検討することもできます。

于 2013-06-04T02:03:50.760 に答える