如果有人能在这方面帮助我,我将不胜感激。我有一个看起来像这样的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="'
'"/>
<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((> 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="'
'"/>
<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">
但看起来像孩子,前面的兄弟姐妹和后面的兄弟姐妹::代码不受支持。
非常感谢您的帮助。
鉴于您可以使用 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> </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"/>