XML to CSV Problem

2019-08-21 19:20发布

I am trying to convert xml to csv. I am facing problem to get child node (like ProdIDT, IDV) as one line a tab delimeted txt file. Child node value is coming close without header. Please look at the below my input and XSL file.

XML

<Product>
<Record>1616200243</Record>
<Not>03</Not>
<ProductId>
<ProdIDT>02</ProdIDT>
<IDV>1616200243</IDV>
</ProductId>
<ProductId>
<ProdIDT>03</ProdIDT>
<IDV>9781616200244</IDV>
</ProductId>
<ProdFormDe>Electronic book text</ProdFormDe>
<EpTy>000</EpTy>
<NoS/>
<Title>
<TitleT>01</TitleT>
<TTx>The Sound of a Wild Snail Eating</TTx>
<Sbt>A Memoir</Sbt>
</Title>
</Product>

My XSL

<xsl:for-each select="//Product/child::*|//Product/self::*">

  <xsl:if test="$fieldNames = 'yes'">

    <xsl:if test="position() = 1 or position()&gt;1">

      <xsl:for-each select="@*">
        <xsl:value-of select="name()"/>

        <xsl:value-of select="$delimiter"/>

      </xsl:for-each>

      <xsl:for-each select="*">
        <xsl:value-of select="name()"/>

        <xsl:if test="position() != last()">
          <xsl:value-of select="$delimiter"/>
        </xsl:if>
      </xsl:for-each>
      <xsl:text>
    </xsl:text>
    </xsl:if>
  </xsl:if>
  <xsl:for-each select="@*">
    <xsl:value-of select="."/>
    <xsl:value-of select="$delimiter"/>
  </xsl:for-each>
  <xsl:for-each select="*">
    <xsl:value-of select="."/>
    <xsl:if test="position() != last()">
      <xsl:value-of select="$delimiter"/>
    </xsl:if>
  </xsl:for-each>
  <xsl:text>

Required Output

Record          Not     ProductId   ProdIDT IDV             ProductId       ProdIDT IDV             ProdFormDe      EpTy    NoS Title           TitleT  TTx     Sbt
1616200243      03                      02      1616200243                      03      9781616200244   Electronic book text            000             01      The Sound of a Wild Snail Eating        A Memoir

Thanks Byomokesh

标签: xml xslt
3条回答
你好瞎i
2楼-- · 2019-08-21 19:49

basically, you need 2 loops. One for-each Product and inside that loop there should be another for all the properties of the Product. And after each product, write out a newline character. Something like this:

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

  <xsl:template match="/">
    <xsl:for-each select="//Product[position()=1]">
      <xsl:for-each select=".//*">
        <xsl:value-of select="name()" />
        <xsl:call-template name="WriteTab" />
      </xsl:for-each>
    </xsl:for-each>
    <xsl:call-template name="WriteNewLine" />

    <xsl:for-each select="//Product">
      <xsl:for-each select=".//*">
        <xsl:value-of select="text()" />
        <xsl:call-template name="WriteTab" />
      </xsl:for-each>
      <xsl:call-template name="WriteNewLine" />
    </xsl:for-each>
  </xsl:template>

  <xsl:template name ="WriteNewLine">
    <xsl:text>
</xsl:text>
  </xsl:template>

  <xsl:template name="WriteTab">
    <xsl:text>&#9;</xsl:text>
  </xsl:template>

查看更多
相关推荐>>
3楼-- · 2019-08-21 19:55

Something like this:

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

<xsl:template match="/">
  <xsl:for-each select="/*//*">
   <xsl:value-of select="concat(name(), '&#9;')"/>
  </xsl:for-each>
  <xsl:text>&#xA;</xsl:text>
  <xsl:for-each select="/*//*">
    <xsl:value-of select="concat(text(), '&#9;')"/>
  </xsl:for-each>
</xsl:template>
</xsl:stylesheet>
查看更多
再贱就再见
4楼-- · 2019-08-21 20:00

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:template match="/*">
        <xsl:apply-templates select="*[1]" mode="header"/>
        <xsl:apply-templates/>
    </xsl:template>
    <xsl:template match="*[not(*)]" mode="header">
        <xsl:value-of
         select="concat(name(),
                        substring('&#x9;&#xA;',
                                  1+boolean(following::*[1][self::Product]
                                            or not(following::*[1])),
                                  1))"/>
    </xsl:template>
    <xsl:template match="*[not(*)]">
        <xsl:value-of
         select="concat(.,
                        substring('&#x9;&#xA;',
                                  1+boolean(following::*[1][self::Product]
                                            or not(following::*[1])),
                                  1))"/>
    </xsl:template>
</xsl:stylesheet>

With this input:

<root>
    <Product>
        <Record>1616200243</Record>
        <Not>03</Not>
        <ProductId>
            <ProdIDT>02</ProdIDT>
            <IDV>1616200243</IDV>
        </ProductId>
        <ProductId>
            <ProdIDT>03</ProdIDT>
            <IDV>9781616200244</IDV>
        </ProductId>
        <ProdFormDe>Electronic book text</ProdFormDe>
        <EpTy>000</EpTy>
        <NoS/>
        <Title>
            <TitleT>01</TitleT>
            <TTx>The Sound of a Wild Snail Eating</TTx>
            <Sbt>A Memoir</Sbt>
        </Title>
    </Product>
</root>

Output:

Record  Not ProdIDT IDV ProdIDT IDV ProdFormDe  EpTy    NoS TitleT  TTx Sbt
1616200243  03  02  1616200243  03  9781616200244   Electronic book text    000     01  The Sound of a Wild Snail Eating    A Memoir
查看更多
登录 后发表回答