XSLT用于包装后续的兄弟元素,具体取决于计数

时间:2011-09-20 22:33:21

标签: xml xslt

我正在试图找出一个相当简单的xslt,但却给了我一些悲伤。基本上,我想从以下xml开始......

<?xml version="1.0" encoding="UTF-8"?>
<TEST>
    <OBR>
        <OBR-1>obr1</OBR-1>
    </OBR>
    <OBX>
        <OBX-1>obx1</OBX-1>
    </OBX>
    <OBX>
        <OBX-1>obx2</OBX-1>
    </OBX>
    <OBR>
        <OBR-1>obr2</OBR-1>
    </OBR>
    <OBX>
        <OBX-1>obx2-1</OBX-1>
    </OBX>
    <OBX>
        <OBX-1>obx2-2</OBX-1>
    </OBX>
    <OBR>
        <OBR-1>obr3</OBR-1>
    </OBR>
    <OBX>
        <OBX-1>obx3-1</OBX-1>
    </OBX>
    <OBX>
        <OBX-1>obx3-2</OBX-1>
    </OBX>
</TEST>

并最终得到以下内容......

<?xml version="1.0" encoding="UTF-8"?>
<TEST>
    <OBR>
        <OBR-1>obr1</OBR-1>
    </OBR>
    <OBX>
        <OBX-1>obx1</OBX-1>
    </OBX>
    <OBX>
        <OBX-1>obx2</OBX-1>
    </OBX>
    <SENSITIVITY>
        <OBR>
            <OBR-1>obr2</OBR-1>
        </OBR>
        <OBX>
            <OBX-1>obx2-1</OBX-1>
        </OBX>
        <OBX>
            <OBX-1>obx2-2</OBX-1>
        </OBX> 
        <OBR>
            <OBR-1>obr3</OBR-1>
        </OBR>
        <OBX>
            <OBX-1>obx3-1</OBX-1>
        </OBX>
        <OBX>
            <OBX-1>obx3-2</OBX-1>
        </OBX>
    </SENSITIVITY>
</TEST>

基本上,一旦到达第二个OBR元素,它和任何后续的OBR和OBX必须包装在SENSITIVITY元素中。初始的xml可能包含也可能没有多个OBR。

感谢。

1 个答案:

答案 0 :(得分:3)

这种简单而简短的转型

<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="OBR[2]">
  <SENSITIVITY>
   <xsl:apply-templates select=".|following-sibling::node()" mode="inGroup"/>
  </SENSITIVITY>
 </xsl:template>

 <xsl:template match="node()" mode="inGroup">
  <xsl:call-template name="identity"/>
 </xsl:template>

 <xsl:template match="*[count(preceding-sibling::OBR) >1]"/>
</xsl:stylesheet>

应用于提供的XML文档

<TEST>
    <OBR>
        <OBR-1>obr1</OBR-1>
    </OBR>
    <OBX>
        <OBX-1>obx1</OBX-1>
    </OBX>
    <OBX>
        <OBX-1>obx2</OBX-1>
    </OBX>
    <OBR>
        <OBR-1>obr2</OBR-1>
    </OBR>
    <OBX>
        <OBX-1>obx2-1</OBX-1>
    </OBX>
    <OBX>
        <OBX-1>obx2-2</OBX-1>
    </OBX>
    <OBR>
        <OBR-1>obr3</OBR-1>
    </OBR>
    <OBX>
        <OBX-1>obx3-1</OBX-1>
    </OBX>
    <OBX>
        <OBX-1>obx3-2</OBX-1>
    </OBX>
</TEST>

生成想要的正确结果

<TEST>
   <OBR>
      <OBR-1>obr1</OBR-1>
   </OBR>
   <OBX>
      <OBX-1>obx1</OBX-1>
   </OBX>
   <OBX>
      <OBX-1>obx2</OBX-1>
   </OBX>
   <SENSITIVITY>
      <OBR>
         <OBR-1>obr2</OBR-1>
      </OBR>
      <OBX>
         <OBX-1>obx2-1</OBX-1>
      </OBX>
      <OBX>
         <OBX-1>obx2-2</OBX-1>
      </OBX>
      <OBR>
         <OBR-1>obr3</OBR-1>
      </OBR>
      <OBX>
         <OBX-1>obx3-1</OBX-1>
      </OBX>
      <OBX>
         <OBX-1>obx3-2</OBX-1>
      </OBX>
   </SENSITIVITY>
</TEST>

<强>解释

  1. identity rule “按原样”复制每个节点。

  2. 模板会覆盖作为其父级第二个OBR子级的OBR元素的标识规则。在这里,我们生成包装元素SENSITIVITY并处理名为"inGroup"的特殊 mode 中的所有后续节点。

  3. 匹配"ingroup"模式中任何元素的模板只调用标识规则。或者,在这里我们可以简单地使用<xsl:copy-of select="."/>指令。

  4. 要禁止身份模板复制到输出(在正常的匿名模式下)第二个OBR之后的元素,我们指定另一个匹配任何此类元素且具有空体的模板规则,这有效地防止任何此类元素被复制到输出。此模板会覆盖并禁止身份规则。