使用XSLT的多行

时间:2018-06-04 09:01:02

标签: xml xslt xslt-1.0 xslt-2.0

如果有人能帮助我,我感激不尽。我有一个看起来像这样的XML:

<root>
<worker>
     <Primary_Key>12345</Primary_Key>
     <First_Name>ABC</First_Name>
     <Last_Name>DEF</Last_Name>         
    <Multiple_Data>
        <Code>MO</Code>
        <Amount>35</Amount>
    </Multiple_Data>
    <Multiple_Data>
        <Code>PA</Code>
        <Amount>45</Amount>
    </Multiple_Data>
</worker>
<worker>
    <Primary_Key>67890</Primary_Key>
    <First_Name>GHI</First_Name>
    <Last_Name>JKL</Last_Name>
    <Multiple_Data>
        <Code>PA</Code>
        <Amount>25</Amount>
    </Multiple_Data>
</worker>
<worker>
    <Primary_Key>11121</Primary_Key>
    <First_Name>MNO</First_Name>
    <Last_Name>PQR</Last_Name>    
</worker</root>

我需要输出完全如下:

  

12345,ABC,DEF,MO,35个
  12345,ABC,DEF,PA,45个
  67890,GHI,JKL,PA,25个
  11121,MNO,PQR ,,

12345有多个数据代码和金额。值显示在单独的行上。 11121没有代码和数量,因此分隔符是唯一显示的分隔符。

这是XSLT,但似乎无法正常工作:

<output method="text"/>

<variable name="delimiter"><text>,</text></variable>    
<variable name="linefeed" select="'&#xd;&#xa;'"/>
<template match="child::Primary_Key">     
    <choose>
        <when test="preceding-sibling::Multiple_Data//child::text() = ''">
            <for-each select="following-sibling::Multiple_Data">

                <value-of select="concat(preceding-sibling::Primary_Key/child::text(), $delimiter, preceding-sibling::First_Name/child::text(), $delimiter, preceding-sibling::Last_Name/child::text(), $delimiter, child::Code/child::text(), $delimiter, child::Amount/child::text())"/>

                <if test="(self::Primary_Key[position() = last()])">
                    <value-of select="$linefeed"/> 
                </if>

            </for-each>
        </when>
        <otherwise>
            <for-each select="child::Primary_Key">                    
                <value-of select="concat(preceding-sibling::Primary_Key/child::text(), $delimiter, preceding-sibling::First_Name/child::text(), $delimiter, preceding-sibling::Last_Name/child::text(), $delimiter, $delimiter )"/>                
                <if test="(self::Primary_Key[position() = last()])">
                    <value-of select="$linefeed"/> 
                </if>

            </for-each>

        </otherwise>

    </choose>                        
</template>
<template match="child::root/worker">
    <apply-templates select="child::Primary_Key"/>
</template>
</transform>

当我尝试在XSLT下面使用它时,它会在顶部和空格给我不必要的新行。 if(position()&gt; 1)无法摆脱输出中的第一个空白行。当然,这里没有显示没有多个数据的工人。

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

<output method="text"/>

<variable name="delimiter"><text>,</text></variable>    
<variable name="linefeed" select="'&#xd;&#xa;'"/>
<template match="child::Primary_Key">     

       <for-each select="following-sibling::Multiple_Data">

                <value-of select="concat(preceding-sibling::Primary_Key/child::text(), $delimiter, preceding-sibling::First_Name/child::text(), $delimiter, preceding-sibling::Last_Name/child::text(), $delimiter, child::Code/child::text(), $delimiter, child::Amount/child::text())"/>                
                <if test="(self::Primary_Key[position() = last()])">
                    <value-of select="$linefeed"/> 
                </if>

            </for-each>

</template>
<template match="child::root/worker">
    <apply-templates select="child::Primary_Key"/>
</template>

还有其他更好的方法来编码,而不在标题中使用此变换吗?

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

我想创建以:

开头的xslt
<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

但看起来像子,前兄弟和后兄弟::代码不受支持。

非常感谢你的帮助。

1 个答案:

答案 0 :(得分:1)

鉴于您可以使用XSLT 2并希望为输入样本中不存在的数据提供一些输出,我建议使用两步转换,其中单独模式中的第一步只是为缺失添加空元素数据,然后默认模式的第二步输出CSV。

如果您可以在oXygen和XSLT 3中使用Saxon 9.8(任何版本)或9.7 PE / EE,您可以轻松设置其他模式

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

  <xsl:output method="text"/>

  <xsl:mode name="add-dummy-data" on-no-match="shallow-copy"/>

  <xsl:variable name="dummy-data">
      <xsl:apply-templates mode="add-dummy-data"/>
  </xsl:variable>

  <xsl:template match="worker[not(Multiple_Data)]" mode="add-dummy-data">
      <xsl:copy>
          <xsl:copy-of select="@*, node()"/>
          <Multiple_Data>
              <Code/>
              <Amount/>
          </Multiple_Data>
      </xsl:copy>
  </xsl:template>

  <xsl:template match="/">
    <xsl:apply-templates select="$dummy-data/root/worker/Multiple_Data"/>
  </xsl:template>

  <xsl:template match="Multiple_Data">
      <xsl:value-of select="../Primary_Key, ../First_Name, ../Last_Name, Code, Amount" separator=","/>
      <xsl:text>&#10;</xsl:text>
  </xsl:template>

</xsl:stylesheet>

请参阅https://xsltfiddle.liberty-development.net/bdxtq1/1

如果您与XSLT 2绑定,则需要使用

<xsl:template match="@* | node()" mode="add-dummy-data">
  <xsl:copy>
    <xsl:apply-templates select="@* | node()" mode="#current"/>
  </xsl:copy>
</xsl:template>

而不是<xsl:mode name="add-dummy-data" on-no-match="shallow-copy"/>