2015-02-17 44 views
0

我是XSL新手,正在寻求解决某些问题的方法。我有XML是这样的:如何使用xslt创建层次结构

<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发票标题和剩余行的发票行。每张发票标题在field1中都有其ID,但发票行中没有发票ID。我知道当行中没有field3时,表示该行是发票行。在其他情况下,它是发票标题。标题行之前的每一行都属于之前的标题行。如何使用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> 
+2

它更容易帮助你得到想要的结果,如果你补充一点,你想拥有你的问题输出XML。 – 2015-02-17 22:04:40

+0

可能是这样的: “P_907” “5912” “2013年5月31日” “2013年5月31日” “2.1.1.M5” “3.1.1。M5" “P_908” “5913” “2013年5月31日” “2013年5月31日” “3.11.M2” pepkas 2015-02-17 22:15:11

+1

这是一个*分组*问题(做一个搜索)。如果你是usi,答案会非常不同ng XSLT 1.0或2.0。 – 2015-02-17 22:56:40

回答

-2

一种解决方案是以下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]) &gt; $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

<xsl:template match="Row[Field3]"> 

该模板写入<Invoice>节点,并通过应用模板复制此的内容。然后通过应用模板mode="copy"来复制以下所有的元素,其没有Field3而没有更多的前面的兄弟元素与Field3元素比当前复制。
此模板复制的内容,但不复制属性,因此的id将从输出中删除。 为避免两次写入元素,空模板 <xsl:template match="Row"/>与通过在模板中应用匹配元素与Field3的模板已处理的所有节点相匹配。

+0

这不会产生请求的输出。这并不奇怪,因为条件'not(following-sibling :: Row [1] [Field3])'没有逻辑对齐(至少我没有看到)。 – 2015-02-17 23:13:14

+0

@ michael.hor257k感谢您的输入,只需再次检查并注意您的意思。将在几分钟内编辑或删除。 – 2015-02-17 23:20:49

+0

非常感谢。这正是我需要的。 – pepkas 2015-02-18 13:23:10

1

我会做到这一点使用的键如下:

<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>