0

XSLTを使用してXMLデータをCSVに変換しようとしています。行はコンマで区切られますが、一部のデータには二重引用符が付いています。変換に次のコードを使用しましたが、データ、特に引用符付きの行を適切に処理しません。

これは私のサンプルデータです

<Add>
<Rowinfo>
<LocatorD>Dwelling  </LocatorD>
<LName> shark </LName>
<L>1</L>
<AArea>Abesinia Passage</AArea>
</Rowinfo>

XSLが上記のデータに適用されると、XSLが生成します

LocatorDesignator,LocatorName,     Locator      ,  Thoroughfare     ,      AddressArea

Dwelling         ,     shark ,       1          ,   Abesinia Passage,

Shop 01-Feb,Shop ,       1   , Casenapes Square ,                   ,

しかし、意図された結果は、

LocatorDesignator,LocatorName,Locator,   Thoroughfare      ,       AddressArea

Dwelling         ,     shark ,  1    ,   Abesinia Passage  ,

Shop 01-Feb      ,     Shop  ,  1    ,    Casenapes Square ,

つまり、これをCSVファイルとして開くと

  • ショップ01-2月、ショップはたまたま1つの列にありました
  • 次のような個別の列の代わりに:

    LocatorDesignator | LocatorName

    ショップ01-2月、ショップ|

それ以外の

LocatorDesignator| LocatorName
Shop 01-Feb      | Shop
4

1 に答える 1

0

このXSLT1.0スタイルシート...

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

<xsl:template match="/">
   <xsl:apply-templates select="*/Rowinfo[1]/*" mode="heading" />
   <xsl:value-of select="'&#x0A;'" />
   <xsl:apply-templates select="*/Rowinfo" />
</xsl:template>

<xsl:template match="Rowinfo/*" mode="heading" >
 <xsl:value-of select="local-name()" />
 <xsl:if test="position() != last()">  
  <xsl:value-of select="','" />
 </xsl:if>  
</xsl:template>

<xsl:template match="Rowinfo">
  <xsl:variable name="line-with-extra-comma">
   <xsl:for-each select="*">
    <xsl:variable name="col-name" select="local-name()" />
    <xsl:if test="../../Rowinfo[1]/*[local-name() = $col-name]">
      <xsl:call-template name="csv-encode" />
      <xsl:value-of select="','" />
    </xsl:if>  
   </xsl:for-each>
  </xsl:variable> 
 <xsl:value-of select="concat(
      substring($line-with-extra-comma, 1,
      string-length($line-with-extra-comma) - 1),
    '&#x0A;')" />
</xsl:template>

<xsl:template name="escape-value">
 <xsl:param name="text" />
 <xsl:choose>
  <xsl:when test="contains($text,'&quot;')">
    <xsl:value-of select="concat( substring-before($text,'&quot;'), '&quot;&quot;')" />
    <xsl:call-template name="escape-value">
      <xsl:with-param name="text" select="substring-after($text,'&quot;')" />
    </xsl:call-template>  
  </xsl:when>
  <xsl:otherwise>
   <xsl:value-of select="$text" /> 
  </xsl:otherwise>  
 </xsl:choose>  
</xsl:template>

<xsl:template name="csv-encode">
 <xsl:choose>
  <xsl:when test="contains(.,',') or starts-with(.,'&quot;')">
   <xsl:value-of select="'&quot;'" />
    <xsl:call-template name="escape-value">
     <xsl:with-param name="text" select="text()" /> 
    </xsl:call-template>  
   <xsl:value-of select="'&quot;'" /> 
  </xsl:when>
  <xsl:otherwise>
   <xsl:value-of select="." /> 
  </xsl:otherwise>  
 </xsl:choose>  
</xsl:template>  

</xsl:stylesheet>

...この入力ドキュメントを取得します...

<Address>
    <Rowinfo>
        <LocatorDesignator>Dwelling  </LocatorDesignator>
        <LocatorName> shark </LocatorName>
        <Locator>1</Locator>
        <AddressArea>Abesinia Passage</AddressArea>
    </Rowinfo>
    <Rowinfo>
        <LocatorDesignator>"Shop 01-Feb</LocatorDesignator>
        <LocatorName>"Shop</LocatorName>
        <Locator>1</Locator>
        <Thoroughfare>Casenapes Square</Thoroughfare>
        <AddressArea/>
    </Rowinfo>
</Address>

...そしてそれをこのcsv出力に変換します...

LocatorDesignator,LocatorName,Locator,AddressArea
Dwelling  , shark ,1,Abesinia Passage
"""Shop 01-Feb","""Shop",1,

警告

私はそれを仮定しました:

  1. 列見出しは、最初の行の子要素によって定義されます。テーブルが空(行なし)になる可能性がある場合は、それに応じて調整する必要があります。
  2. 名前による要素は、最初の行と同じ順序で後続の行に表示されます。
  3. 後続の行には、無関係な子要素が含まれている可能性がありますが、欠落していることはありません。無関係な要素は削除されます。
  4. Csv出力は適切なcsv出力です。値にコンマが含まれているか、二重引用符で始まっている場合、値は二重引用符でエスケープされます。
  5. すべての値は単一行です。複数行のcsvは、このスクリプトでは処理されません。
  6. 出力ラインターミネータはLFです。CR.LFなどが必要な場合は、それに応じて調整してください。
于 2012-08-26T08:41:03.240 に答える