代码之家  ›  专栏  ›  技术社区  ›  Benjamin Ortuzar

基于属性包装同级节点

  •  2
  • Benjamin Ortuzar  · 技术社区  · 15 年前

    使用XSLT,如何包装为属性共享相同值的同级。

    假设我需要包装一个或多个 <amendment/> <chapter/> 他们也属于他们。

    <section>
          <heading>some heading text</heading>
          <amendment num='1' chapter='1'>
                <foo/>
          </amendment>
          <amendment num='2' chapter='1'>
                <bar/>
          </amendment>
          <amendment num='3' chapter='2'>
                <baz/>
          </amendment>
          <heading>some heading text</heading>
          <amendment num='4' chapter='3'>
                <baz/>
          </amendment>
    </section>
    

    <section>
          <heading>some heading text</heading>
          <chapter num="1">
                <amendment num='1'>
                      <foo/>
                </amendment>
                <amendment num='2'>
                      <bar/>
                </amendment>
          </chapter>
          <chapter num="2">
                <amendment num='3'>
                      <baz/>
                </amendment>
          </chapter>
          <heading>some heading text</heading>
          <chapter num="3">
                <amendment num='4'>
                      <baz/>
                </amendment>
          </chapter>
    </section>
    

    注1:在源XML中,修改总是按章节排序。

    4 回复  |  直到 15 年前
        1
  •  1
  •   user357812 user357812    15 年前

    此样式表:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:key name="kAmendementByChapter" match="amendment" use="@chapter"/>
        <xsl:template match="node()|@*" name="identity">
            <xsl:copy>
                <xsl:apply-templates select="node()|@*"/>
            </xsl:copy>
        </xsl:template>
        <xsl:template match="amendment[count(.|key('kAmendementByChapter',
                                                   @chapter)[1])=1]">
            <chapter num="{@chapter}">
                <xsl:apply-templates select="key('kAmendementByChapter',@chapter)"
                                     mode="copy"/>
            </chapter>
        </xsl:template>
        <xsl:template match="amendment"/>
        <xsl:template match="amendment" mode="copy">
            <xsl:call-template name="identity"/>
        </xsl:template>
        <xsl:template match="@chapter"/>
    </xsl:stylesheet>
    

    输出:

    <section>
        <heading>some heading text</heading>
        <chapter num="1">
            <amendment num="1">
                <foo></foo>
            </amendment>
            <amendment num="2">
                <bar></bar>
            </amendment>
        </chapter>
        <chapter num="2">
            <amendment num="3">
                <baz></baz>
            </amendment>
        </chapter>
        <heading>some heading text</heading>
        <chapter num="3">
            <amendment num="4">
                <baz></baz>
            </amendment>
        </chapter>
    </section>
    

    注意 :Copy all(标识规则),分组在@chapter上。

        2
  •  0
  •   Flynn1179    15 年前

    如果使用的是XSLT 1,可以使用Muenchian分组方法,如下所示:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:key name="chapter" use="@chapter" match="amendment" />
    
      <xsl:template match="section">
        <xsl:copy>
          <xsl:apply-templates select="heading | amendment[generate-id() = generate-id(key('chapter',@chapter)[1])]" />
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="amendment">
        <xsl:element name="chapter">
          <xsl:attribute name="num">
            <xsl:value-of select="@chapter" />
          </xsl:attribute>
          <xsl:apply-templates select="key('chapter', @chapter)" mode="withoutchapter"/>
        </xsl:element>
      </xsl:template>
    
      <xsl:template match="amendment" mode="withoutchapter">
        <xsl:copy>
          <xsl:apply-templates  select="@*[(name() != 'chapter')] | node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
      </xsl:template>
    </xsl:stylesheet>
    

    amendment 用那个章节做标记。

    这里有两个警告:第一,任何没有章节的修正都将从输出中删除。

    所以,如果你这样做(为了清楚起见,缩写):

    <amendment num='1' chapter='1' />
    <heading>heading text</heading>
    <amendment num='2' chapter='1' />
    

    它将输出:

    <chapter num='1'>
      <amendment num='1' />
      <amendment num='2' />
    </chapter>
    <heading>heading text</heading>
    
        3
  •  0
  •   Nick Jones    15 年前

    因为您的修改是按章节排序的,所以您可以不使用键,而只需查看后面和前面的元素。以下措施应该有效:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    <xsl:template match="amendment[not(@chapter = preceding-sibling::amendment[1]/@chapter)]">
      <chapter num="{@chapter}">
        <xsl:variable name="chapter" select="@chapter"/>
          <amendment num="{@num}">
            <xsl:apply-templates/>
          </amendment>
        <xsl:apply-templates select="following-sibling::amendment[1][@chapter = $chapter]">
          <xsl:with-param name="chapter" select="@chapter"/>
        </xsl:apply-templates>
      </chapter>
    </xsl:template>
    
    <xsl:template match="amendment">
      <xsl:param name="chapter"/>
      <xsl:if test="$chapter">
          <amendment num="{@num}">
            <xsl:apply-templates/>
          </amendment>
          <xsl:apply-templates select="following-sibling::amendment[1][@chapter = $chapter]">
            <xsl:with-param name="chapter" select="$chapter"/>
          </xsl:apply-templates>
      </xsl:if>
    </xsl:template>
    
      <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>
    
        4
  •  0
  •   Dimitre Novatchev    15 年前

    感谢@Alejandro和@Flynn1179注意到这个解决方案的初始版本中的一个错误——现在已经更正了!

    :

    <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="kbyChapter" match="amendment"
         use="@chapter"/>
    
     <xsl:template match="node()" name="identity">
         <xsl:copy>
           <xsl:apply-templates select="@*"/>
           <xsl:apply-templates select="node()[1]"/>
         </xsl:copy>
         <xsl:apply-templates select="following-sibling::node()[1]"/>
     </xsl:template>
    
     <xsl:template match="amendment"/>
     <xsl:template match=
     "amendment[not(@chapter=preceding-sibling::amendment[1]/@chapter)]">
      <chapter num="{@chapter}">
       <xsl:apply-templates select="key('kbyChapter',@chapter)" mode="copy"/>
      </chapter>
      <xsl:apply-templates select=
        "key('kbyChapter',@chapter)[last()]/following-sibling::node()[1]"/>
     </xsl:template>
    
     <xsl:template match="*" mode="copy">
      <xsl:copy>
       <xsl:apply-templates select="@*|node()[1]"/>
      </xsl:copy>
     </xsl:template>
    
     <xsl:template match="@*">
      <xsl:copy-of select="."/>
     </xsl:template>
    
     <xsl:template match="@chapter"/>
    </xsl:stylesheet>
    

    在提供的XML文档上应用时 amendment ):

    <section>
          <heading>some heading text</heading>
          <amendment num='1' chapter='1'>
                <foo/>
          </amendment>
          <amendment num='2' chapter='1'>
                <bar/>
          </amendment>
          <amendment num='3' chapter='2'>
                <baz/>
          </amendment>
          <heading>some heading text</heading>
          <amendment num='4' chapter='3'>
                <baz/>
          </amendment>
    </section>
    

    产生想要的,正确的结果 :

    <section>
        <heading>some heading text</heading>
        <chapter num="1">
            <amendment num="1">
                <foo/>
            </amendment>
            <amendment num="2">
                <bar/>
            </amendment>
        </chapter>
        <chapter num="2">
            <amendment num="3">
                <baz/>
            </amendment>
        </chapter>
        <heading>some heading text</heading>
        <chapter num="3">
            <amendment num="4">
                <baz/>
            </amendment>
        </chapter>
    </section>