我有以下XML结构:
<root>
<product>
<name>
<book1>data for book1</book1>
<book12>data for book12</book12>
<book13>data for book13</book13>
<book14>data for book14</book14>
</name>
<info>
<data1>data for data1</data1>
<data2>data for data2</data2>
<data3>data for data3<data3>
<data4>data for data4</data4>
<data5>data for data5</data5>
<data n+1>data n+1</data n+1>
</info>
<pictures>
<pic1>data for pic1</pic1>
<pic2>data for pic2</pic2>
<pic3>data for pic3</pic3>
<pic4>data for pic4</pic4>
<pic n+1>data for pic n+1</pic n+1>
</pictures>
</product>
<product>
.
.
.
.
.
</product>
.
.
.
.
</root>
现在我需要在每个节点产品中复制data5,book14和整个节点图片,因此输出xml将如下所示:
<root>
<product>
<node_that_i_would_name_1>
<node_that_i_would_name_2>
<node_that_i_would_name_3>
<node_that_i_would_name_4>
<book14>data for book14</book14>
</node_that_i_would_name_4>
<node_that_i_would_name_5>
<data5>data for data5</data5>
</node_that_i_would_name_5>
<picturesA>
<pic1A>
<pic2A>
<pic3A>
<pic4A>
<pic n+1A>
</picturesA>
<empty_node_at_the_end_that_i_will_name></empty_node_at_the_end_that_i_will_name>
</node_that_i_would_name_3>
</node_that_i_would_name_2>
</node_that_i_would_name_1>
<name>
<book1>data for book1</book1>
<book12>data for book12</book12>
<book13>data for book13</book13>
<book14>data for book14</book14>
</name>
<info>
<data1>data for data1</data1>
<data2>data for data2</data2>
<data3>data for data3<data3>
<data4>data for data4</data4>
<data5>data for data5</data5>
<data n+1>data n+1</data n+1>
</info>
<pictures>
<pic1>data for pic1</pic1>
<pic2>data for pic2</pic2>
<pic3>data for pic3</pic3>
<pic4>data for pic4</pic4>
<pic n+1>data for pic n+1</pic n+1>
</pictures>
</product>
<product>
.
.
.
.
.
</product>
.
.
.
.
</root>
每件事都应该保持不变,只有这些数据必须以上面的方式复制和重新规划到节点中。有没有简单的方法用xslt做到这一点?
答案 0 :(得分:3)
当您看到这样的问题时,您的第一个想法应该是Identity Transform
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
所有这一切本身就是将所有现有节点复制到输出文档。但这意味着您只需为要转换的任何特定元素编写模板,在您的情况下为 product 元素。 (XSLT将优先考虑与特定节点名称相匹配的模板,而不是身份模板使用的更通用的匹配项。)
因此,产品的模板将具有此结构。从本质上讲,它仍然是身份转换,但会引入额外的代码。
<xsl:template match="product">
<xsl:copy>
<xsl:apply-templates select="@*" />
<!-- Code to create new nodes and create extra copies of existing ones goes here -->
<xsl:apply-templates select="node()"/>
</xsl:copy>
编辑:请注意,需要在任何元素之前复制属性!
例如,要在新元素中创建 book14 元素的副本,只需添加以下代码:
<newnode1>
<xsl:apply-templates select="name/book14"/>
</newnode1>
对于Picture元素,要允许使用元素名称上的额外后缀复制它,您将拥有一个与子元素匹配的模板,以及一个(可选)参数,该参数随后将用于创建元素名称
<xsl:template match="pictures/*">
<xsl:param name="suffix" />
<xsl:element name="{concat(local-name(), $suffix)}">
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>
然后,该模板将在两个不同的地方使用。通常与结构匹配的地方,以及您想要创建额外副本的地方。但在后一种情况下,您可以设置参数:
<xsl:apply-templates select="pictures/*">
<xsl:with-param name="suffix" select="'A'" />
</xsl:apply-templates>
尝试将此XSLT作为示例,您应该可以使用那些您真正想要自己命名的节点进行扩展....
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="product">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<newnode>
<newnode1>
<xsl:apply-templates select="name/book14"/>
</newnode1>
<newnode2>
<xsl:apply-templates select="info/data5"/>
</newnode2>
<picturesA>
<xsl:apply-templates select="pictures/*">
<xsl:with-param name="suffix" select="'A'" />
</xsl:apply-templates>
</picturesA>
</newnode>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="pictures/*">
<xsl:param name="suffix" />
<xsl:element name="{concat(local-name(), $suffix)}">
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>