我有一个看起来像这样的xml:
<ShoppingList>
<MoneyIHaveToSpend>20.00</MoneyIHaveToSpend>
<Item>
<Name>Apples</Name>
<Price>1.00</Price>
</Item>
<Item>
<Name>Oranges</Name>
<Price>1.00</Price>
</Item>
<AdditionalInfo>...</AdditionalInfo>
</ShoppingList>
我想将“items”包装到GroceryList中,如下所示:
<ShoppingList>
<MoneyIHaveToSpend>20.00</MoneyIHaveToSpend>
<GroceryList>
<Item>
<Name>Apples</Name>
<Price>1.00</Price>
</Item>
<Item>
<Name>Oranges</Name>
<Price>1.00</Price>
</Item>
</GroceryList>
<AdditionalInfo>...</AdditionalInfo>
</ShoppingList>
“ShoppingList”中只有一个子列表。我将如何使用xslt进行此操作?
我尝试执行以下操作,但拆分<GroceryList>
和</GroceryList>
会给我编译错误。我知道其余的都是错的,但由于编译错误,我甚至无法测试它或乱用它:
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ShoppingList">
<xsl:apply-templates select="/ShoppingList/Item"/>
<xsl:if test="position() = 1">
<GroceryList> <!-- Error: "XML element is not closed" -->
<xsl:apply-templates/>
</xsl:if>
<xsl:if test="???">
</GroceryList> <!-- Error: "No open tag found" -->
</xsl:if>
</xsl:template>
答案 0 :(得分:3)
您的XSLT必须是格式良好的XML,因此您无法在一个xsl:if
中启动元素并在另一个元素中关闭它。
就像C. M. Sperberg-McQueen建议的那样,从identity transform开始并从那里覆盖。
示例(如果ShoppingList
孩子的顺序无关紧要):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ShoppingList">
<xsl:copy>
<xsl:apply-templates select="@*|node()[not(self::Item)]"/>
<GroceryList>
<xsl:apply-templates select="Item"/>
</GroceryList>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
如果订单确实重要,您可以这样做:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()" name="ident">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Item[1]">
<GroceryList>
<xsl:apply-templates select=".|following-sibling::Item" mode="keep"/>
</GroceryList>
</xsl:template>
<xsl:template match="Item" mode="keep">
<!--You could overwrite identity transform here.-->
<xsl:call-template name="ident"/>
</xsl:template>
<xsl:template match="Item"/>
</xsl:stylesheet>
以上内容非常通用,但如果您始终知道子ShoppingList
将具有什么,或者您不需要修改任何元素,则可以简化。 (您可以使用xsl:copy-of
代替xsl:apply-templates
。)
答案 1 :(得分:1)
另一个解决方案:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="utf-8" method="xml"/>
<xsl:template match="ShoppingList">
<ShoppingList>
<xsl:variable name="firstItemName"><xsl:value-of select="./Item/Name/text()"/></xsl:variable>
<xsl:apply-templates>
<xsl:with-param name="firstItem"><xsl:value-of select="$firstItemName"/></xsl:with-param>
</xsl:apply-templates>
</ShoppingList>
</xsl:template>
<xsl:template match="Item">
<xsl:param name="firstItem"/>
<xsl:choose>
<xsl:when test="./Name/text()=$firstItem">
<xsl:element name="GroceryList">
<xsl:apply-templates select="../Item"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="MoneyIHaveToSpend|AdditionalInfo|text()">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
答案 2 :(得分:1)
节点不“开始”和“结束”,它们是父母和孩子在树上的点。您正在尝试编写XSLT,就好像它将开始和结束标记输出为可分离操作,而不是构建节点树。树上的节点是不可分割的。
如果您的分组问题与示例所示一样简单,那么最简单的解决方案将使用如下模板:
<xsl:template match="ShoppingList">
<xsl:apply-templates select="MoneyIHaveToSpend"/>
<GroceryList>
<xsl:apply-templates select="Item"/>
</GroceryList>
<xsl:apply-templates select="AdditionalInfo"/>
</xsl:template>
当您阅读本文时,请不要将<GroceryList>
和</GroceryList>
视为单独的说明。模板主体包含三个指令序列:apply-templates,GroceryList和apply-templates,GroceryList指令包含内容(“序列构造函数”),其中包含生成GroceryList节点内容的指令。