2010-07-13 146 views
0

我对转换的正确表达式有些问题。我正在生成CSV文件。 我可以很容易地生成以下CSV:将XML转换为CSV - 详细信息

"version","","stuff", 
    "version1version2","annotation1annotation2","yadda", 

不过,我想为子域是逗号分隔的字符串中的不同情况,具体如下:

"version","","stuff", 
"version1,version2","annotation1,annotation2","yadda", 

我输入看起来是像

<?xml version="1.0" encoding="UTF-8"?> 
<collection> 
    <record> 
    <datafield tag="020"> 
     <subfield code="a">version</subfield> 
    </datafield> 
    <datafield tag="040"> 
     <subfield code="b">stuff</subfield> 
    </datafield> 
    </record> 
    <record> 
    <datafield tag="020"> 
     <subfield code="a">version1</subfield> 
     <subfield code="9">annotation1</subfield> 
    </datafield> 
    <datafield tag="020"> 
     <subfield code="a">version2</subfield> 
     <subfield code="9">annotation2</subfield> 
    </datafield> 
    <datafield tag="040"> 
     <subfield code="b">yadda</subfield> 
    </datafield> 
    </record> 
</collection> 

使用下面的XSL(和xsltproc的)

<?xml version="1.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="collection/record"/> 
</xsl:template> 

<xsl:template match="record"> 
    <xsl:text>"</xsl:text> 
    <xsl:apply-templates select="datafield[@tag='020']/subfield[@code='a']"/> 
    <xsl:text>",</xsl:text> 

    <xsl:text>"</xsl:text> 
    <xsl:apply-templates select="datafield[@tag='020']/subfield[@code='9']"/> 
    <xsl:text>",</xsl:text> 

    <xsl:text>"</xsl:text> 
    <xsl:apply-templates select="datafield[@tag='040']/subfield[@code='b']"/> 
    <xsl:text>",</xsl:text> 

    <xsl:text> 
</xsl:text> 
</xsl:template> 

我猜想以下的兄弟姐妹::或不(位置()=最后())与呼叫模板的组合将涉及,但我还没有击中一个工作的解决方案。任何帮助?

我不是在寻找一个通用的XML-to-csv转换 - 任何面向这个特定数据集的东西都没问题。

回答

1
<xsl:template match="record"> 
    <xsl:text>"</xsl:text> 
    <xsl:apply-templates select="datafield[@tag='020']/subfield[@code='a']" /> 
    <xsl:text>",</xsl:text> 

    <xsl:text>"</xsl:text> 
    <xsl:apply-templates select="datafield[@tag='020']/subfield[@code='9']" /> 
    <xsl:text>",</xsl:text> 

    <xsl:text>"</xsl:text> 
    <xsl:apply-templates select="datafield[@tag='040']/subfield[@code='b']" /> 
    <xsl:text>",</xsl:text> 

    <xsl:text>&#xa;</xsl:text><!-- line break --> 
</xsl:template> 

<xsl:template match="subfield"> 
    <xsl:value-of select="." /> 
    <xsl:if test="position() != last()">,</xsl:if> 
</xsl:template> 

对于较大的输入数据集,引入键将导致更好的整体性能:

<xsl:key name="kSubfield" match="datafield/subfield" use=" 
    concat(
    generate-id(ancestor::record), '|', parent::datafield/@tag, '|', @code 
) 
" /> 

<!-- ... --> 

<xsl:template match="record"> 
    <xsl:variable name="recordId" select="generate-id()" /> 

    <xsl:text>"</xsl:text> 
    <xsl:apply-templates select="key('kSubfield', concat($recordId, '|020|a'))" /> 
    <xsl:text>",</xsl:text> 

    <xsl:text>"</xsl:text> 
    <xsl:apply-templates select="key('kSubfield', concat($recordId, '|020|9'))" /> 
    <xsl:text>",</xsl:text> 

    <xsl:text>"</xsl:text> 
    <xsl:apply-templates select="key('kSubfield', concat($recordId, '|040|b'))" /> 
    <xsl:text>",</xsl:text> 

    <xsl:text>&#xa;</xsl:text><!-- line break --> 
</xsl:template> 
+0

这是......非常容易。谢谢! – Jurgen 2010-07-13 12:46:43

+0

@Jurgen:很高兴听到它适合你。 :-) – Tomalak 2010-07-13 12:48:10

1

在更一般的方式,该样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 
    <xsl:key name="field" match="subfield" use="concat(../@tag,'&#xA;',@code)"/> 
    <xsl:variable name="fields" select="/*/*/*/subfield[count(.|key('field',concat(../@tag,'&#xA;',@code))[1])=1]"/> 
    <xsl:template match="record"> 
     <xsl:variable name="me" select="."/> 
     <xsl:for-each select="$fields"> 
      <xsl:text>"</xsl:text> 
      <xsl:apply-templates select="$me/*/*[concat(../@tag,'&#xA;',@code)=concat(current()/../@tag,'&#xA;',current()/@code)]"/> 
      <xsl:text>"</xsl:text> 
      <xsl:if test="position() != last()">,</xsl:if> 
     </xsl:for-each> 
     <xsl:text>&#xA;</xsl:text> 
    </xsl:template> 
    <xsl:template match="subfield"> 
     <xsl:value-of select="."/> 
     <xsl:if test="position() != last()">,</xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

结果:

"version","stuff","" 
"version1,version2","yadda","annotation1,annotation2"