如何使用XSLT来组装一个XML层次(How can I use XSLT to assemble

2019-09-17 13:25发布

鉴于这种XML

 <Xml> <Thing id="1" > <Foo id="11" parentId="12"/> <Foo id="12"/> </Thing> <Thing id="2" parentId="1" /> <Thing id="3" parentId="2" /> <Thing id="4"> <Foo id="11" parentId="15"/> <Foo id="12" parentId="14"/> <Foo id="13" parentId="11"/> <Foo id="14" parentId="15"/> <Foo id="15"/> </Thing> </Xml> 

我想抓住的兄弟姐妹的每一个集合,并把它们组装成自己的层次。

与parentId的值,每一个“物”的节点,应该相应的事情节点下窝。 与parentId的值,每一个“富”节点,应该相应美孚节点下的鸟巢 - 但仅限于它的兄弟姐妹。 这个例子有两套富兄弟姐妹。

我试图创建此:

 <Xml> <Thing id="1" > <Foo id="12"> <Foo id="11" parentId="12"/> </Foo> <Thing id="2" parentId="1" > <Thing id="3" parentId="2" /> </Thing> </Thing> <Thing id="4" > <Foo id="14" parentId="12"> <Foo id="12" parentId="14"/> </Foo> <Foo id="15"> <Foo id="11" parentId="15"> <Foo id="13" parentId="11"/> </Foo> </Foo> </Thing> </Xml> 

这个例子很接近: 我如何使用XSLT 1.0结构添加到非heirarchal XML文件?

我使用的身份模板保留所有节点和属性。 然后我想压倒一切的模板匹配的有兄弟姐妹的所有节点上(之后或之前),使得兄弟姐妹的@parentId值等于我的@id值。 我能来最接近的是硬编码的ID / parentId的值来匹配。

 <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output indent="yes"/> <!-- override identity rule with template to match on a node who has siblings, where sibling/@parentId == ./@id --> <xsl:template match="node()[@id='1' and (preceding-sibling::*[@parentId = 1] or following-sibling::*[@parentId = 1])]"> <captured> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </captured> </xsl:template> <!-- identity rule --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet> 

我看不出如何抓住当前节点@id值的基础上的parentId的值的XPath匹配的兄弟姐妹的谓词使用。

然后我想窝在当前节点的兄弟姐妹它的下面,那里的兄弟姐妹@ParentId等于我@id。

Answer 1:

首先,做注意到所提供的XML文档中的错误

    <Foo id="12" parentId="14"/>
    <Foo id="13" parentId="11"/>
    <Foo id="14" parentId="12"/>

之间有一个圆形关系Fooid 12和Foo14 。 这使得一个周期,而不是“层级”。 此外,这两个Foo元素是从层次结构的顶部无法访问请正确的

这一转变

<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:key name="kElemById" match="*"
   use="concat(generate-id(..), '+', @id)"/>
 <xsl:key match="*" name="kDescendants"
  use="concat(generate-id(key('kElemById', 
                              concat(generate-id(..), '+',@parentId))),
             '+', @parentId)"/>

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

 <xsl:template match="/*">
  <Xml>
   <xsl:apply-templates select="*[not(@parentId)]"/>
  </Xml>
 </xsl:template>

 <xsl:template match="*/*">
   <xsl:copy>
    <xsl:apply-templates select="@*"/>

    <xsl:apply-templates select="*[not(@parentId)]"/>

    <xsl:apply-templates select=
       "key('kDescendants', concat(generate-id(), '+',  @id))"/>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

当施加在提供的XML文档

<Xml>
    <Thing id="1"  >
        <Foo id="11" parentId="12"/>
        <Foo id="12"/>
    </Thing>
    <Thing id="2" parentId="1" />
    <Thing id="3" parentId="2" />
    <Thing id="4">
        <Foo id="11" parentId="15"/>
        <Foo id="12" parentId="14"/>
        <Foo id="13" parentId="11"/>
        <Foo id="14" parentId="12"/>
        <Foo id="15"/>
    </Thing>
</Xml>

产生正确的结果,不包括任何不可达元素

<Xml>
   <Thing id="1">
      <Foo id="12">
         <Foo id="11" parentId="12"/>
      </Foo>
      <Thing id="2" parentId="1">
         <Thing id="3" parentId="2"/>
      </Thing>
   </Thing>
   <Thing id="4">
      <Foo id="15">
         <Foo id="11" parentId="15">
            <Foo id="13" parentId="11"/>
         </Foo>
      </Foo>
   </Thing>
</Xml>


文章来源: How can I use XSLT to assemble an XML Hierarchy
标签: xslt