Php 包装XML节点组

Php 包装XML节点组,php,xml,xslt,Php,Xml,Xslt,我正在使用PHP5,我需要以以下形式转换XML: <list> <item label="(1)">some text</item> <item label="(2)"> <anotherNode>some text</anotherNode <item label="a">some text</item> <item label="b"

我正在使用PHP5,我需要以以下形式转换XML:

<list>
    <item label="(1)">some text</item>
    <item label="(2)">
        <anotherNode>some text</anotherNode
        <item label="a">some text</item>
        <item label="b">some text</item>          
    </item>
</list>

一些文本
一些文本
正如您在上面看到的,我需要将包装器节点添加到任何尚未由“列表”节点包装的“项目”节点

将源xml转换为目标xml有哪些可能的解决方案

更新:

注1:如果
节点尚未包装,则任何单个或组
节点都需要由
节点包装

注2:需要维护内容的顺序

注3: 如果在
前后有
节点。 它应该改变这一点:

<list>
    <item label="(1)">some text</item>
    <item label="(2)">
        <item label="a">some text</item>
        <item label="b">some text</item>          
        <anotherNode>some text</anotherNode>
        <item label="c">some text</item>
        <item label="d">some text</item>          
    </item>
</list>

一些文本
一些文本
一些文本
一些文本
一些文本
一些文本
为此:

<list>
    <item label="(1)">some text</item>
    <item label="(2)">
        <list> <!-- opening new wrapper node-->
            <item label="a">some text</item>
            <item label="b">some text</item>          
        </list> <!-- closing new wrapper node-->
        <anotherNode>some text</anotherNode>
        <list> <!-- opening new wrapper node-->
            <item label="c">some text</item>
            <item label="d">some text</item>
        </list> <!-- closing new wrapper node-->
    </item>
</list>

一些文本
一些文本
一些文本
一些文本
一些文本
一些文本
谢谢,

此样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="@*|node()" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()[1]" />
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]" />
    </xsl:template>
    <xsl:template match="*[not(self::list)]
                          /item[not(preceding-sibling::*[1][self::item])]">
        <list>
            <xsl:call-template name="identity"/>
        </list>
        <xsl:apply-templates select="following-sibling::node()
                                      [not(self::item)][1]" />
    </xsl:template>
    <xsl:template match="*[not(self::list)]
                          /item[not(following-sibling::*[1][self::item])]">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()[1]" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kItemByFirstSibling"
             match="item[preceding-sibling::*[1][self::item]]"
             use="generate-id(preceding-sibling::item
                               [not(preceding-sibling::*[1][self::item])][1])"/>
    <xsl:template match="@*|node()" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[not(self::list)]/item"/>
    <xsl:template match="*[not(self::list)]
                          /item[not(preceding-sibling::*[1][self::item])]"
                  priority="1">
        <list>
            <xsl:for-each select=".|key('kItemByFirstSibling',generate-id())">
                <xsl:call-template name="identity"/>
            </xsl:for-each>
        </list>
    </xsl:template>
</xsl:stylesheet>

此转换

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*" name="identity">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="item/item[1]">
  <list>
   <xsl:apply-templates mode="copy"
    select=".| following-sibling::item"/>
  </list>
 </xsl:template>

 <xsl:template match="item" mode="copy">
  <xsl:call-template name="identity"/>
 </xsl:template>

 <xsl:template match="item/item[not(position()=1)]"/>
</xsl:stylesheet>
<list>
    <item label="(1)">some text</item>
    <item label="(2)">
        <anotherNode>some text</anotherNode>
        <item label="a">some text</item>
        <item label="b">some text</item>
    </item>
</list>
<list>
   <item label="(1)">some text</item>
   <item label="(2)">
      <anotherNode>some text</anotherNode>
      <list>
         <item label="a">some text</item>
         <item label="b">some text</item>
      </list>
   </item>
</list>
<list>
    <item label="(1)">some text</item>
    <item label="(2)">
        <item label="a">some text</item>
        <item label="b">some text</item>
        <anotherNode>some text</anotherNode>
        <item label="c">some text</item>
        <item label="d">some text</item>
    </item>
</list>
<list>
   <item label="(1)">some text</item>
   <item label="(2)">
      <list>
         <item label="a">some text</item>
         <item label="b">some text</item>
      </list>
      <anotherNode>some text</anotherNode>
      <list>
         <item label="c">some text</item>
         <item label="d">some text</item>
      </list>
   </item>
</list>
对以下XML文档执行此转换时

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*" name="identity">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="item/item[1]">
  <list>
   <xsl:apply-templates mode="copy"
    select=".| following-sibling::item"/>
  </list>
 </xsl:template>

 <xsl:template match="item" mode="copy">
  <xsl:call-template name="identity"/>
 </xsl:template>

 <xsl:template match="item/item[not(position()=1)]"/>
</xsl:stylesheet>
<list>
    <item label="(1)">some text</item>
    <item label="(2)">
        <anotherNode>some text</anotherNode>
        <item label="a">some text</item>
        <item label="b">some text</item>
    </item>
</list>
<list>
   <item label="(1)">some text</item>
   <item label="(2)">
      <anotherNode>some text</anotherNode>
      <list>
         <item label="a">some text</item>
         <item label="b">some text</item>
      </list>
   </item>
</list>
<list>
    <item label="(1)">some text</item>
    <item label="(2)">
        <item label="a">some text</item>
        <item label="b">some text</item>
        <anotherNode>some text</anotherNode>
        <item label="c">some text</item>
        <item label="d">some text</item>
    </item>
</list>
<list>
   <item label="(1)">some text</item>
   <item label="(2)">
      <list>
         <item label="a">some text</item>
         <item label="b">some text</item>
      </list>
      <anotherNode>some text</anotherNode>
      <list>
         <item label="c">some text</item>
         <item label="d">some text</item>
      </list>
   </item>
</list>

一些文本
一些文本
一些文本
一些文本
一些文本
一些文本
生成所需的正确结果

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*" name="identity">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="item/item[1]">
  <list>
   <xsl:apply-templates mode="copy"
    select=".| following-sibling::item"/>
  </list>
 </xsl:template>

 <xsl:template match="item" mode="copy">
  <xsl:call-template name="identity"/>
 </xsl:template>

 <xsl:template match="item/item[not(position()=1)]"/>
</xsl:stylesheet>
<list>
    <item label="(1)">some text</item>
    <item label="(2)">
        <anotherNode>some text</anotherNode>
        <item label="a">some text</item>
        <item label="b">some text</item>
    </item>
</list>
<list>
   <item label="(1)">some text</item>
   <item label="(2)">
      <anotherNode>some text</anotherNode>
      <list>
         <item label="a">some text</item>
         <item label="b">some text</item>
      </list>
   </item>
</list>
<list>
    <item label="(1)">some text</item>
    <item label="(2)">
        <item label="a">some text</item>
        <item label="b">some text</item>
        <anotherNode>some text</anotherNode>
        <item label="c">some text</item>
        <item label="d">some text</item>
    </item>
</list>
<list>
   <item label="(1)">some text</item>
   <item label="(2)">
      <list>
         <item label="a">some text</item>
         <item label="b">some text</item>
      </list>
      <anotherNode>some text</anotherNode>
      <list>
         <item label="c">some text</item>
         <item label="d">some text</item>
      </list>
   </item>
</list>

一些文本
一些文本
一些文本
一些文本
一些文本
一些文本

您在原始问题中没有提到这一点,因此可能不需要。但是,如果输入有多个需要包装的
元素序列,这些元素由其他同级元素彼此分离,例如:

<list>
    <item label="(1)">some text</item>
    <item label="(2)">
        <item label="a">some text</item>
        <item label="b">some text</item>          
        <anotherNode>some text</anotherNode>
        <item label="c">some text</item>
        <item label="d">some text</item>          
    </item>
</list>

一些文本
一些文本
一些文本

.

好问题(+1)。请参阅我的答案,了解XSLT精神下的简短解决方案。@Benjamin Ortuzar:您忘记接受答案了吗?仍然不完全满意?@Dimitre:+1表示模式解决方案。@Dimitre:如果在
之前和之后都有
元素,会发生什么情况?您的解决方案将把它们全部放在
之前@本杰明,在这种情况下会发生什么?@LarsH:观察得好。未指定具有其他名称和项目列表的兄弟项的所需顺序。我的解决方案保留了第一个
和任何非项同级项之间的相对(文档)顺序。我认为这是很自然的。如果需要另一种排序,那么很容易修改解决方案以满足新的需求,前提是在这些组的前面和后面都有元素,它们应该有自己的包装器。内容的顺序应该保留。@Benjamin Ortuzar和@LarsH:我已经更新了我的答案,以便解决方案满足最新的要求。:)@亚历杭德罗:看我对迪米特的评论。。。假设所有需要包装的项元素(即同一个非列表元素的子元素)都是连续的,那么这个方法就可以了。@LarsH:正如我在notes中所写的,第一个样式表将第一个
之后的任何节点包装起来。第二个样式表包装任何
,不包含
列表
父项,相对顺序(同级之间)将是第一个
的相对顺序。我认为这是一个公平的问题,但只在OP想要输出siblings
列表
家长时才重要。我需要像第二个示例那样单独包装他们。