如何使用 xslt 创建层次结构
How create hierarchy using xslt
我是 XSL 的新手,正在寻找解决问题的方法。我有 xml 类似的东西:
<Table>
<Row Id="1">
<Field1>"P_907"</Field1>
<Field2>"5912"</Field2>
<Field3>"2013/05/31"</Field3>
<Field4>"2013/05/31"</Field4>
</Row>
<Row Id="2">
<Field1>"2.1.1.M5"</Field1>
</Row>
<Row Id="3">
<Field1>"3.1.1.M5"</Field1>
</Row>
<Row Id="4">
<Field1>"P_908"</Field1>
<Field2>"5913"</Field2>
<Field3>"2013/05/31"</Field3>
<Field4>"2013/05/31"</Field4>
</Row>
<Row Id="5">
<Field1>"3.11.M2"</Field1>
</Row>
</Table>
其中行 ID=1 和行 ID=4 是 header 发票,其余行是发票行。每张发票 header 在字段 1 中都有其 ID,但发票行中没有发票 ID。我知道当行中没有 field3 时,这意味着该行是发票行。在其他情况下,它是发票 header。 header 行之前的每一行都属于前 header 行。如何使用 xslt 创建具有适当发票层次结构的 xml?
输出 xml 可能是这样的:
<Invoice>
<Field1>"P_907"</Field1>
<Field2>"5912"</Field2>
<Field3>"2013/05/31"</Field3>
<Field4>"2013/05/31"</Field4>
<Row>
<Field1>"2.1.1.M5"</Field1>
</Row>
<Row>
<Field1>"3.1.1.M5"</Field1>
</Row>
</Invoice>
<Invoice>
<Field1>"P_908"</Field1>
<Field2>"5913"</Field2>
<Field3>"2013/05/31"</Field3>
<Field4>"2013/05/31"</Field4>
<Row>
<Field1>"3.11.M2"</Field1>
</Row>
</Invoice>
一种解决方案是以下 XSLT:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="Table">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="Row[Field3]">
<xsl:variable name="invoice-count" select="count(preceding-sibling::Row[Field3]) + 1"/>
<Invoice>
<xsl:apply-templates/>
<xsl:apply-templates select="following-sibling::Row[not(Field3)
and not(count(preceding-sibling::Row[Field3]) > $invoice-count)]" mode="copy"/>
</Invoice>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Row" mode="copy">
<xsl:copy>
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Row"/>
</xsl:transform>
当应用于您的输入时 XML 产生输出
<Invoice>
<Field1>"P_907"</Field1>
<Field2>"5912"</Field2>
<Field3>"2013/05/31"</Field3>
<Field4>"2013/05/31"</Field4>
<Row>
<Field1>"2.1.1.M5"</Field1>
</Row>
<Row>
<Field1>"3.1.1.M5"</Field1>
</Row>
</Invoice>
<Invoice>
<Field1>"P_908"</Field1>
<Field2>"5913"</Field2>
<Field3>"2013/05/31"</Field3>
<Field4>"2013/05/31"</Field4>
<Row>
<Field1>"3.11.M2"</Field1>
</Row>
</Invoice>
一个模板匹配包含 Field3
:
的所有 Row
个元素
<xsl:template match="Row[Field3]">
此模板写入一个 <Invoice>
节点并通过应用模板复制此 Row
的内容。然后,通过应用模板 Row
复制所有没有 Field3
且前面带有 Field3
的兄弟 Row
元素不多于当前 Row
的所有后续 silbing Row
元素=22=].
此模板复制 Row
的内容但不复制属性,因此将从输出中删除 Row
的 id
。
为避免两次写入 Row
元素,空模板
<xsl:template match="Row"/>
匹配已通过在模板中应用模板处理的所有 Row
节点,该模板将 Row
元素与 Field3
.
相匹配
我会使用以下键来执行此操作:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:key name="Rows" match="Row[not(Field3)]" use="generate-id(preceding-sibling::Row[Field3][1])"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Row[Field3]">
<Invoice>
<xsl:apply-templates select="node()"/>
<xsl:apply-templates select="key('Rows', generate-id())" mode="followingRows"/>
</Invoice>
</xsl:template>
<xsl:template match="Row" mode="followingRows">
<xsl:copy><xsl:apply-templates select="node()"/></xsl:copy>
</xsl:template>
<xsl:template match="Row"/>
</xsl:stylesheet>
我是 XSL 的新手,正在寻找解决问题的方法。我有 xml 类似的东西:
<Table>
<Row Id="1">
<Field1>"P_907"</Field1>
<Field2>"5912"</Field2>
<Field3>"2013/05/31"</Field3>
<Field4>"2013/05/31"</Field4>
</Row>
<Row Id="2">
<Field1>"2.1.1.M5"</Field1>
</Row>
<Row Id="3">
<Field1>"3.1.1.M5"</Field1>
</Row>
<Row Id="4">
<Field1>"P_908"</Field1>
<Field2>"5913"</Field2>
<Field3>"2013/05/31"</Field3>
<Field4>"2013/05/31"</Field4>
</Row>
<Row Id="5">
<Field1>"3.11.M2"</Field1>
</Row>
</Table>
其中行 ID=1 和行 ID=4 是 header 发票,其余行是发票行。每张发票 header 在字段 1 中都有其 ID,但发票行中没有发票 ID。我知道当行中没有 field3 时,这意味着该行是发票行。在其他情况下,它是发票 header。 header 行之前的每一行都属于前 header 行。如何使用 xslt 创建具有适当发票层次结构的 xml?
输出 xml 可能是这样的:
<Invoice>
<Field1>"P_907"</Field1>
<Field2>"5912"</Field2>
<Field3>"2013/05/31"</Field3>
<Field4>"2013/05/31"</Field4>
<Row>
<Field1>"2.1.1.M5"</Field1>
</Row>
<Row>
<Field1>"3.1.1.M5"</Field1>
</Row>
</Invoice>
<Invoice>
<Field1>"P_908"</Field1>
<Field2>"5913"</Field2>
<Field3>"2013/05/31"</Field3>
<Field4>"2013/05/31"</Field4>
<Row>
<Field1>"3.11.M2"</Field1>
</Row>
</Invoice>
一种解决方案是以下 XSLT:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="Table">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="Row[Field3]">
<xsl:variable name="invoice-count" select="count(preceding-sibling::Row[Field3]) + 1"/>
<Invoice>
<xsl:apply-templates/>
<xsl:apply-templates select="following-sibling::Row[not(Field3)
and not(count(preceding-sibling::Row[Field3]) > $invoice-count)]" mode="copy"/>
</Invoice>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Row" mode="copy">
<xsl:copy>
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Row"/>
</xsl:transform>
当应用于您的输入时 XML 产生输出
<Invoice>
<Field1>"P_907"</Field1>
<Field2>"5912"</Field2>
<Field3>"2013/05/31"</Field3>
<Field4>"2013/05/31"</Field4>
<Row>
<Field1>"2.1.1.M5"</Field1>
</Row>
<Row>
<Field1>"3.1.1.M5"</Field1>
</Row>
</Invoice>
<Invoice>
<Field1>"P_908"</Field1>
<Field2>"5913"</Field2>
<Field3>"2013/05/31"</Field3>
<Field4>"2013/05/31"</Field4>
<Row>
<Field1>"3.11.M2"</Field1>
</Row>
</Invoice>
一个模板匹配包含 Field3
:
Row
个元素
<xsl:template match="Row[Field3]">
此模板写入一个 <Invoice>
节点并通过应用模板复制此 Row
的内容。然后,通过应用模板 Row
复制所有没有 Field3
且前面带有 Field3
的兄弟 Row
元素不多于当前 Row
的所有后续 silbing Row
元素=22=].
此模板复制 Row
的内容但不复制属性,因此将从输出中删除 Row
的 id
。
为避免两次写入 Row
元素,空模板
<xsl:template match="Row"/>
匹配已通过在模板中应用模板处理的所有 Row
节点,该模板将 Row
元素与 Field3
.
我会使用以下键来执行此操作:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:key name="Rows" match="Row[not(Field3)]" use="generate-id(preceding-sibling::Row[Field3][1])"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Row[Field3]">
<Invoice>
<xsl:apply-templates select="node()"/>
<xsl:apply-templates select="key('Rows', generate-id())" mode="followingRows"/>
</Invoice>
</xsl:template>
<xsl:template match="Row" mode="followingRows">
<xsl:copy><xsl:apply-templates select="node()"/></xsl:copy>
</xsl:template>
<xsl:template match="Row"/>
</xsl:stylesheet>