xml – XSLT – 在分隔符上爆炸节点

我需要一个XSLT 1.0来分解分隔符上的
XML节点并创建单个节点.

例如,如果分隔符为“_”且XML为:

<root>
    <a_b_c>hello<a_b_c>
    <a_b_c1>world</a_b_c1>
</root>

结果XML应该是:

<root>
    <a>
        <b>
            <c>hello</c>
            <c1>world</c1>
        </b>
    </a>
</root>

不包含分隔符的节点应按原样输出.
我真的需要在XSLT1.0中使用它
谢谢您的帮助.

最佳答案 这种转变:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

  <xsl:key name="kSameNameAdj" match="*"
  use="concat(generate-id(..),
              '+',
              generate-id(preceding-sibling::*[not(name()=name(current()))][1])
              )"/>

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

 <xsl:template match="/">
  <xsl:variable name="vrtfPass1">
   <xsl:apply-templates select="node()"/>
  </xsl:variable>

  <xsl:apply-templates select="ext:node-set($vrtfPass1)" mode="compress"/>
 </xsl:template>

 <xsl:template name="explode" match=
  "*[contains(name(),'_')
   and not(substring(name(),1,1)='_')
   and not(substring(name(), string-length(name()))='_')
    ]">
    <xsl:param name="pName" select="name()"/>
    <xsl:param name="pText" select="text()"/>

  <xsl:choose>
   <xsl:when test="not($pName)">
    <xsl:value-of select="$pText"/>
   </xsl:when>
   <xsl:otherwise>
      <xsl:element name="{substring-before(concat($pName, '_'), '_')}">
       <xsl:call-template name="explode">
         <xsl:with-param name="pName" select="substring-after($pName, '_')"/>
         <xsl:with-param name="pText" select="$pText"/>
       </xsl:call-template>
      </xsl:element>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:template>

  <xsl:template match="/" name="fold" mode="compress">
  <xsl:param name="pDoc" select="/"/>

  <xsl:choose>
    <xsl:when test="not($pDoc//*[name()=name(following-sibling::*[1])])">
      <xsl:copy-of select="$pDoc"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="vrtfThisPass">
        <xsl:apply-templates select="$pDoc/*" mode="compress"/>
      </xsl:variable>

      <xsl:call-template name="fold">
        <xsl:with-param name="pDoc" select="ext:node-set($vrtfThisPass)"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
 </xsl:template>

 <xsl:template match="node()|@*" mode="compress">
   <xsl:copy>
     <xsl:apply-templates select="@*|node()[1]" mode="compress"/>
   </xsl:copy>
   <xsl:apply-templates select="following-sibling::node()[1]" mode="compress"/>
 </xsl:template>

 <xsl:template match="*[name()=name(following-sibling::*[1])]" mode="compress">
  <xsl:element name="{name()}">
    <xsl:apply-templates mode="compress" select=
    "key('kSameNameAdj',
          concat(generate-id(..),
                 '+',generate-id(preceding-sibling::*)
                 )
         )/node()"/>
  </xsl:element>
  <xsl:apply-templates mode="compress" select=
  "key('kSameNameAdj',
          concat(generate-id(..),
                 '+',generate-id(preceding-sibling::*)
                 )
         )
          [last()]/following-sibling::node()[1]
   "/>
 </xsl:template>
</xsl:stylesheet>

当应用于以下XML文档时(提供的文档,扩展为更具挑战性):

<root>
   <x>This is:</x>
     <a_b_c>hello</a_b_c>
     <a_b_c_d>my</a_b_c_d>
     <a_b_c1>wonderful</a_b_c1>
     <a_b_c>world</a_b_c>
     <a_b>!</a_b>
   <y>The End</y>
</root>

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

<root>
   <x>This is:</x>
   <a>
      <b>
         <c>hello<d>my</d>
         </c>
         <c1>wonderful</c1>
         <c>world</c>!</b>
   </a>
   <y>The End</y>
</root>

说明:

0.1.这是一个多次转换.
第一遍将XML文档转换为:

<root>
   <x>This is:</x>
   <a>
      <b>
         <c>hello</c>
      </b>
   </a>
   <a>
      <b>
         <c>
            <d>my</d>
         </c>
      </b>
   </a>
   <a>
      <b>
         <c1>wonderful</c1>
      </b>
   </a>
   <a>
      <b>
         <c>world</c>
      </b>
   </a>
   <a>
      <b>!</b>
   </a>
   <y>The End</y>
</root>

0.2.随后的传递,每个都将具有相同名称的任何相邻元素组压缩到具有该名称的单个元素中 – 然后递归地处理结果,直到不再存在具有相同名称的多于一个相邻兄弟元素的任何组.

0.3.第一遍使用identity rule.

0.4.下一次传递在“压缩”模式下使用fine-grade identity模板.

点赞