xml - XSLT 根据计数包装后续的同级元素

标签 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。

谢谢。

最佳答案

这个简单而简短的转换:

<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 child 。这里我们生成包装器元素 SENSITIVITY并在特殊的 mode 中处理所有后续节点,命名为"inGroup" .

  3. 匹配"ingroup"中任意元素的模板mode 简单地调用身份规则。或者,在这里我们可以简单地使用 <xsl:copy-of select="."/>说明。

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

关于xml - XSLT 根据计数包装后续的同级元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7492605/

相关文章:

java - 如何使用 xquery 在 java 中处理非常大的 xml 文件,如 150mb

Java从XML解析值 <tag><value/></tag>

java - 测试 Spring 配置错误需要什么 XML 文件?

xml - 如何为整个表格创建边框

xml - 如何在 XSLT 中编写身份转换来保留所选节点的子节点?

XSLT 从选择中排除一个特定节点

java - 使用 Grails 脚手架时使用 XML 进行响应

html - 调试 'Error loading stylesheet: XPath parse failure: Name or Nodetype test expected:'

java - 如何从 XSL 输出缩进中排除某些元素?

android - 无法从代码中找到已声明的 XML 样式