当前位置 : 主页 > 网页制作 > xml >

xml – xslt 1.0合并空元素名称

来源:互联网 收集:自由互联 发布时间:2021-06-13
关于使用xslt 1.0的一个快速问题,你可以帮助我.我有一个输入xml,如下所示 Root FirstNameBob/FirstName LastNameMarley/LastName IDBM1234/ID Songs Song EmptyElements/EmptyElements SongNameNo woman no cry/SongName Year1974
关于使用xslt 1.0的一个快速问题,你可以帮助我.我有一个输入xml,如下所示

<Root>
    <FirstName>Bob</FirstName>
    <LastName>Marley</LastName>
    <ID>BM1234</ID>
    <Songs>
        <Song>
            <EmptyElements></EmptyElements>
            <SongName>No woman no cry</SongName>
            <Year>1974</Year>
            <album></album>
            <studio></studio>
            <rating></rating>
        </Song>
    </Songs>
</Root>

输出需要看起来像

<Root>
    <FirstName>Bob</FirstName>
    <LastName>Marley</LastName>
    <ID>BM1234</ID>
    <Songs>
        <Song>
            <EmptyElements>album, studio, rating</EmptyElements>
            <SongName>No woman no cry</SongName>
            <Year>1974</Year>
        </Song>
    </Songs>
</Root>

所以基本上将所有空元素的逗号分隔列表放入EmptyElements标记中.

这种转变:

<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()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="EmptyElements" priority="5">
    <xsl:copy>
      <xsl:apply-templates mode="enumerate" select=
      "../*[not(self::EmptyElements) and not(node())]" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Songs/Song/*" mode="enumerate">
    <xsl:value-of select="substring(',', not(position() = 1), 1)"/>
    <xsl:value-of select="name()"/>
  </xsl:template>
  <xsl:template match="Songs/Song/*[not(node())]"/>
</xsl:stylesheet>

应用于提供的源XML文档时:

<Root>
    <FirstName>Bob</FirstName>
    <LastName>Marley</LastName>
    <ID>BM1234</ID>
    <Songs>
        <Song>
            <EmptyElements></EmptyElements>
            <SongName>No woman no cry</SongName>
            <Year>1974</Year>
            <album></album>
            <studio></studio>
            <rating></rating>
        </Song>
    </Songs>
</Root>

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

<Root>
   <FirstName>Bob</FirstName>
   <LastName>Marley</LastName>
   <ID>BM1234</ID>
   <Songs>
      <Song>
         <EmptyElements>album,studio,rating</EmptyElements>
         <SongName>No woman no cry</SongName>
         <Year>1974</Year>
      </Song>
   </Songs>
</Root>

说明:

>选择执行时,标识规则将“按原样”复制匹配的节点
>匹配Songs / Song / * [not(node())]的模板,当选择执行时,不执行任何操作,这会导致“删除”(不复制)输出中的匹配节点.
>匹配EmptyElements的模板具有比上述“删除”模板更高的优先级,因此选择在任何EmptyElements元素上执行.
>将匹配的EmptyElements元素浅层复制到输出,然后通过将模板枚举模板应用于所有空的siblings-elements来生成其内容(正文).
>最后,模式枚举中的模板匹配Song元素的任何子元素,该元素是Songs元素的子元素.它由< xsl:apply-templates>选择执行.上面步骤4中的指令,仅适用于EmptyElements元素的空元素兄弟节点.此模板执行两项操作:a)输出逗号,如果这不是node-list中的第一个节点; b)输出匹配元素的名称.这样,输出EmptyElements元素的空兄弟元素的所有名称,用逗号分隔.

更新:

亲爱的读者,
我们有一个同伴的答案,这个问题以或简单地开头:
并且暗示它比这个答案中的代码更简单.

而不是告诉你这个答案比简单地简单:-answer,我总结了一些与简单相关的事实,你可以自己做出结论.在下表中,每个左子列中的值都是针对此的当前解决方案.每个右侧子列中的值仅适用于Or:-solution:

除此之外,简单地说: – 解决方案也具有潜在的性能和一定的可流动性问题 – 请参阅此片段:

<xsl:if test="position()!=last()">
                <xsl:text>, </xsl:text>
             </xsl:if>

与当前解决方案使用的内容相比:

not(position() = 1)

见Dr. Michael Kay’s recommendation,后者是“比这更好的编码方式”,他解释了为什么:

“Why? Because however hard the optimizer works, the last() function is hard
work: it involves some kind of lookahead. With “position() ne last()” the
lookahead might be limited to one element, but it’s still a lot more
complicated than testing whether the position is 1.

With streaming coming along, the latter formulation is also more likely to
be streamable (because lookahead is impossible with streaming).”

结论:每当有人告诉我们:“或者简单地说:”,在将他们的陈述视为理所当然之前采取一些指标是很好的…

网友评论