如果有人能帮助我,我感激不尽。我有一个看起来像这样的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()&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="'
'"/>
<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">
但看起来像子,前兄弟和后兄弟::代码不受支持。
非常感谢你的帮助。
答案 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> </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"/>