XSLT:根据其他元素的存在添加具有可变数量的子元素的新节点

问题描述:

我试图根据XML中其他元素的存在性来添加具有可变数量的子元素的新节点文件。这里是我开始用一个简单的例子:XSLT:根据其他元素的存在添加具有可变数量的子元素的新节点

输入:

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

我需要添加一个新的节点(父/ SecondChild),与基于元素创建的子元素在列表节点中。输出应该是这样的(减去我的意见!):

所需的输出:

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

但我在一个不知如何创建NewFruit子元素(在我的帮助!评论是)动态地基于存在水果元素FirstChild节点。任何援助将非常感激 - 我只是不知道在这一点上走什么方向。

UPDATE:

我的问题的回答工作了我提供的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> 

我需要添加一个新的节点(父母/ 1级/ NewLevel2/NewNode),一些子元素是基于列表节点中的元素创建的。输出应该是这样的:

所需的输出:

<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

我不明白你的问题。你说“基于XML文档中其他元素的存在”。 “其他地方”究竟在哪里?我在源XML中只看到一个列表。什么 - 如果有的话 - 应该是输出中两个列表之间的区别? – 2014-10-03 03:22:38

+0

(在你编辑之后)我仍然不明白你的问题。你只是试图在输出的两个地方复制相同的列表,还是应该在两者之间有所不同? – 2014-10-03 03:42:58

+0

请注意,在您的输入中没有'NewLevel2'元素,因此''不匹配任何内容,因此也不会执行任何操作。 **所以你目前的输出不是你说的那样。** – 2014-10-03 03:48:41

如下您可以调整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">

+0

非常感谢!这个解决方案完全适用于我提供的XML,但是当我在我的实际XML上尝试时,它没有正确转换。所以我做了我的XML格式的精确副本,并在原始问题中粘贴更新,如果您不介意再看一下?再次,我真的很感谢你的帮助。 – lcf0285 2014-10-03 03:32:32

+0

@ lcf0285很高兴我能够帮助你。我刚更新了我更新问题的答案。 – 2014-10-03 07:54:53