XSLT将我的自定义XML转换为CSV

时间:2016-03-19 23:43:48

标签: xml csv xslt

我希望使用&#34 ;;"将我的自定义XML转换为csv。作为值分隔符。这是我的XML:

<?xml version="1.0" encoding="utf-8"?>
<root>
    <operators>
        <item>
            <lfbis>1234567</lfbis>
            <name>Stefan Maier</name>
            <company />
            <street>Testweg 7</street>
            <citycode>95131</citycode>
            <city>Hof</city>
            <controlbody>BIKO</controlbody>
            <productdata>
                <item>Rinder</item>
                <item>9</item>
            </productdata>
        </item>
        <item>
            <lfbis>5671234</lfbis>
            <name>Antom Mueller</name>
        <company>Berghof</company>
            <street>Testweg 8</street>
            <citycode>95111</citycode>
            <city>Bamberg</city>
            <controlbody>BIKO</controlbody>
            <productdata>
                <item>Rinder</item>
                <item>9</item>
            </productdata>
        </item>
    </operators>
</root> 

到目前为止我已经管理过了(使用stackoverflow线程 XML to CSV Using XSLT,特别是使用@Tomalak在他的回答...a version with configurable parameters that you can set programmatically中写的代码)来使用以下xslt转换:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" encoding="utf-8" />

  <xsl:param name="delim" select="';'" />
  <xsl:param name="quote" select="'&quot;'" />
  <xsl:param name="break" select="'&#xA;'" />

  <xsl:template match="/">
    <xsl:apply-templates select="root/operators/item" />
  </xsl:template>

  <xsl:template match="item">
    <xsl:apply-templates />
    <!--<xsl:if test="following-sibling::*">-->
      <xsl:value-of select="concat($delim, $break)" />
    <!--</xsl:if>-->
  </xsl:template>

  <xsl:template match="*">
    <xsl:value-of select="normalize-space()" />
    <xsl:if test="following-sibling::*">
      <xsl:value-of select="$delim" />
    </xsl:if>
  </xsl:template>

  <xsl:template match="text()" />

</xsl:stylesheet>

...我使用xsltproc得到以下结果:

1234567;Stefan Maier;;Testweg 7;95131;Hof;BIKO;Rinder 9;
5671234;Antom Mueller;Berghof;Testweg 8;95111;Bamberg;BIKO;Rinder 9;

现在,我想要实现的是 productdata 元素的 item 子元素也被视为csv结果中的值。所以我需要一个&#34 ;;&#34;而不是&#34; &#34;值 Rinder 9 之间的(空格),例如我的csv看起来像:

1234567;Stefan Maier;;Testweg 7;95131;Hof;BIKO;Rinder;9;
5671234;Antom Mueller;Berghof;Testweg 8;95111;Bamberg;BIKO;Rinder;9;

2 个答案:

答案 0 :(得分:2)

一种简单的方法是改变

<xsl:template match="*">

<xsl:template match="*[not(*)]">

匹配没有子元素的元素。效果是当apply-templates命中productData元素时,没有匹配的模板规则,因此默认启动,即将模板应用于子项。

然而,这需要改变处理分隔符的策略。在你的情况下,它相当容易,因为你想在包括最后一项之类的每个项目之后使用分号:所以只需在输出每个项目后无条件地添加分号,并且不要在行的末尾添加另一个分号。

答案 1 :(得分:1)

以下是Tomalak代码的改编

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="text" encoding="utf-8" />

  <xsl:param name="delim" select="';'" />
  <xsl:param name="quote" select="'&quot;'" />
  <xsl:param name="break" select="'&#xA;'" />

  <xsl:template match="/">
    <xsl:apply-templates select="root/operators/item" />
  </xsl:template>

  <xsl:template match="root/operators/item">
    <xsl:apply-templates select=".//*[not(*)]"/>
    <xsl:value-of select="$break" />
  </xsl:template>

  <xsl:template match="*">
    <xsl:if test="position() > 1">
      <xsl:value-of select="$delim"/>
    </xsl:if>
    <xsl:value-of select="normalize-space()" />
  </xsl:template>

  <xsl:template match="text()" />

</xsl:stylesheet>

由于你有两种类型的item元素,我需要一个相当明确的匹配模式。