使用xslt,如何添加在第一次出现之前开始,在最后一次出现项目之后结束的xml节点?
我有一个如下所示的xml:使用xslt,如何添加在第一次出现之前开始,在最后一次出现项目之后结束的xml节点?,xml,xslt,Xml,Xslt,我有一个如下所示的xml: <ShoppingList> <MoneyIHaveToSpend>20.00</MoneyIHaveToSpend> <Item> <Name>Apples</Name> <Price>1.00</Price> </Item> <Item> <Name>Or
<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>
<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>
20
苹果
1
橘子
1
...
我想将“项目”包装到杂货店列表中,如下所示:
<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>
20
苹果
1
橘子
1
...
“ShoppingList”中只有一个子列表。我将如何使用xslt来实现这一点
我试着做如下的事情,但是将
和
分开会导致编译错误。我意识到其余部分无论如何都是错误的,但由于编译错误,我甚至无法测试或处理它:
<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>
您的XSLT必须是格式良好的XML,因此不能在一个
xsl:if
中启动一个元素,然后在另一个中关闭它
就像C.M.斯珀伯格·麦奎因建议的那样,从一个开始,然后从那里重写
示例(如果购物列表
子项的顺序无关紧要):
如果顺序确实重要,您可以这样做:
<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>
<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
)另一种解决方案:
<?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>
节点不是“开始”和“结束”,它们是具有父节点和子节点的树中的点。您试图编写XSLT,就好像它将开始和结束标记作为可分离的操作输出一样,而不是构建节点树。树上的节点是不可分割的
如果分组问题如示例所示简单,则最简单的解决方案将使用以下模板:
<xsl:template match="ShoppingList">
<xsl:apply-templates select="MoneyIHaveToSpend"/>
<GroceryList>
<xsl:apply-templates select="Item"/>
</GroceryList>
<xsl:apply-templates select="AdditionalInfo"/>
</xsl:template>
当你读到这篇文章时,不要把
和
看作是单独的说明。模板正文包含一个由三条指令组成的序列:apply templates、GroceryList和apply templates,GroceryList指令的内容(“序列构造函数”)包含生成GroceryList节点内容的指令。我还没有试着运行它,但我认为它不能作为XSLT2.0样式表使用。在2.0中,的xsl:value中的select
返回序列中的所有项。在1.0中,它只返回第一个。因此,如果使用
,变量实际上将有两项:苹果和橙子。在1.0中,您只需要苹果
。如果您将版本更改为1.0,此样式表可能会工作,但我认为您仍然会有一个额外的Oranges
项输出。此外,当您使用xsl:variable
(或xsl:param
,xsl:attribute
等)时,请尝试使用选择属性。如果不需要,则在不需要时创建一个RTF(结果树片段)。下面是您的firstItemName
重写的示例:
@DanielHaley-感谢您的指点!我在1.0中测试了它,没问题,但是你提出了一些非常好的观点。