我正在尝试根据XML文档中其他元素的存在来添加具有可变数量的子元素的新节点。这是我开始的简化示例:
输入:
<Parent>
<FirstChild>
<List>
<!--There could be an unlimited number of different Fruit elements in this list-->
<Fruit A="Apples"/>
<Fruit B="Bananas"/>
<!--...-->
</List>
</FirstChild>
</Parent>
我需要添加一个新节点(Parent / SecondChild),其子元素是根据 List 节点中的元素创建的。输出应该是这样的(减去我的评论!):
期望输出:
<Parent>
<FirstChild>
<List>
<!--There could be an unlimited number of Fruit elements in this list-->
<Fruit A="Apples"/>
<Fruit B="Bananas"/>
<!--...-->
</List>
</FirstChild>
<SecondChild>
<NewList>
<!--A separate <NewFruit> element needs to be added below based on the existence of the <Fruit> elements in <List> above-->
<NewFruit A="Apples"/>
<NewFruit B="Bananas"/>
<!--...-->
</NewList>
</SecondChild>
</Parent>
我知道如何使用如下转换添加 SecondChild 节点和子元素:
变换:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes" exclude-result-prefixes="xs fn xdt">
<xsl:output method="xml" version="1.0" encoding="UTF-8" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Parent">
<Parent>
<xsl:apply-templates select="@*|*"/>
<SecondChild>
<NewList>
</NewList>
</SecondChild>
</Parent>
</xsl:template>
</xsl:stylesheet>
这给出了以下输出:
当前输出:
<Parent>
<FirstChild>
<List>
<!--There could be an unlimited number of Fruit elements in this list-->
<Fruit A="Apples"/>
<Fruit B="Bananas"/>
<!--...-->
</List>
</FirstChild>
<SecondChild>
<NewList>
<!--HELP!-->
</NewList>
</SecondChild>
</Parent>
但我不知道如何根据 Fruit 元素的存在动态创建 NewFruit 子元素(我的HELP!评论)在 FirstChild 节点中。任何帮助都将非常感激 - 我只是不确定此时的方向。
更新
我的问题的回复适用于我提供的XML(谢谢!),但它不适用于我实际使用的XML(出于保密原因我无法粘贴)。下面的XML完全模仿了我正在使用的格式:
输入:
<Parent>
<Level1>
<Level2>
<List>
<!--There could be an unlimited number of different Fruit elements in this list-->
<Fruit A="Apples"/>
<Fruit B="Bananas"/>
</List>
</Level2>
<NewLevel2>
</NewLevel2>
</Level1>
</Parent>
我需要添加一个新节点(Parent / Level1 / NewLevel2 / NewNode),其中包含一些根据 List 节点中的元素创建的子元素。输出应如下所示:
期望输出:
<Parent>
<Level1>
<Level2>
<List>
<!--There could be an unlimited number of Fruit elements in this list-->
<Fruit A="Apples"/>
<Fruit B="Bananas"/>
</List>
</Level2>
<NewLevel2>
<NewNode>
<NewChildNode>
<NewChildNode1/>
<NewList>
<!--A separate <NewFruit> element needs to be added below based on the existence of the <Fruit> elements in <List> above-->
<NewFruit A="Apples"/>
<NewFruit B="Bananas"/>
</NewList>
</NewChildNode>
</NewNode>
</NewLevel2>
</Level1>
</Parent>
这是我正在使用的XSLT:
变换:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes" exclude-result-prefixes="xs fn xdt">
<xsl:output method="xml" version="1.0" encoding="UTF-8" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="NewLevel2">
<NewLevel2>
<xsl:apply-templates select="@*|*"/>
<NewNode>
<NewChildNode>
<NewChildNode1/>
<NewList>
<xsl:for-each select="*/List/Fruit">
<NewFruit>
<xsl:apply-templates select="@*|node()"/>
</NewFruit>
</xsl:for-each>
</NewList>
</NewChildNode>
</NewNode>
</NewLevel2>
</xsl:template>
</xsl:stylesheet>
这给出了以下输出:
当前输出:
<Parent>
<Level1>
<Level2>
<List>
<!--There could be an unlimited number of different Fruit elements in this list-->
<Fruit A="Apples"/>
<Fruit B="Bananas"/>
</List>
</Level2>
<NewLevel2>
<NewNode>
<NewChildNode>
<NewChildNode1/>
<NewList/>
</NewChildNode>
</NewNode>
</NewLevel2>
</Level1>
</Parent>
因此NewList元素为空 - 由于某种原因未创建NewFruit子节点。但是,我不明白为什么当我发布的原始XML确实正确转换时这不起作用?
答案 0 :(得分:1)
您可以按如下方式调整XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:xdt="http://www.w3.org/2005/xpath-datatypes"
exclude-result-prefixes="xs fn xdt">
<xsl:output method="xml" version="1.0" encoding="UTF-8"
omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Parent">
<Parent>
<xsl:apply-templates select="@*|*"/>
<SecondChild>
<NewList>
<xsl:for-each select="*/List/Fruit">
<NewFruit>
<xsl:apply-templates select="@* | node()"/>
</NewFruit>
</xsl:for-each>
</NewList>
</SecondChild>
</Parent>
</xsl:template>
</xsl:stylesheet>
结果:
<Parent>
<FirstChild>
<List>
<Fruit A="Apples"/>
<Fruit B="Bananas"/>
<!--...-->
</List>
</FirstChild>
<SecondChild>
<NewList>
<NewFruit A="Apples"/>
<NewFruit B="Bananas"/>
</NewList>
</SecondChild>
</Parent>
更新:当您更新问题(输入XML以及所需的输出)时,以下调整后的XSLT会提供新的所需输出:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:xdt="http://www.w3.org/2005/xpath-datatypes"
exclude-result-prefixes="xs fn xdt">
<xsl:output method="xml" version="1.0" encoding="UTF-8"
omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Parent">
<Parent>
<xsl:apply-templates select="@*|*"/>
</Parent>
</xsl:template>
<xsl:template match="NewLevel2">
<NewLevel2>
<NewNode>
<NewChildNode>
<NewChildNode1/>
<NewList>
<xsl:for-each select="//Parent//List/Fruit">
<NewFruit>
<xsl:apply-templates select="@*|node()"/>
</NewFruit>
</xsl:for-each>
</NewList>
</NewChildNode>
</NewNode>
</NewLevel2>
</xsl:template>
</xsl:stylesheet>
XML输入:
<Parent>
<Level1>
<Level2>
<List>
<Fruit A="Apples"/>
<Fruit B="Bananas"/>
</List>
</Level2>
<NewLevel2>
</NewLevel2>
</Level1>
</Parent>
XML输出:
<Parent>
<Level1>
<Level2>
<List>
<Fruit A="Apples"/>
<Fruit B="Bananas"/>
</List>
</Level2>
<NewLevel2>
<NewNode>
<NewChildNode>
<NewChildNode1/>
<NewList>
<NewFruit A="Apples"/>
<NewFruit B="Bananas"/>
</NewList>
</NewChildNode>
</NewNode>
</NewLevel2>
</Level1>
</Parent>
正如michael.hor257k已经提到的那样,您的模板匹配NewLevel2
不会生成任何输出,因为NewLevel2
只是输入XML中的空元素。因此,要获得所需的输出,只需调整XSLT以使模板匹配为NewLevel2
生成NewLevel2
的输出的空<xsl:for-each select="//Parent//List/Fruit">
,而不是此模板的当前节点(为空),但来自根目录的水果列表 - {{1}}。