首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >XSLT:从平面到分层​al结构

XSLT:从平面到分层​al结构
EN

Stack Overflow用户
提问于 2014-10-22 15:06:02
回答 1查看 126关注 0票数 1

我需要转换成这样的平面结构

代码语言:javascript
复制
 <root>
    <H>1</H>
    <I>1-1</I>
    <I>1-2</I>
    <I>1-3</I>
    <H>2</H>
    <I>2-1</I>
    <I>2-2</I>
  </root>

在一个像这样的

代码语言:javascript
复制
   <root>
        <H>
           1
           <I>1-1</I>
           <I>1-2</I>
           <I>1-3</I>
        </H>
        <H>
           2
           <I>2-1</I>
           <I>2-2</I>
        </H>
     </root>

我用这种方式尝试了源结构上的每一种方法

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
 >
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="root">
       <root>
          <xsl:for-each select="child::node()">
             <xsl:if test="self::H">
                <H>
                   <xsl:copy-of select="@* | node()"/>
                   <xsl:call-template name="copyI"/>
                </H>
             </xsl:if>
          </xsl:for-each>
       </root>
    </xsl:template>

    <xsl:template name="copyI">
       <xsl:for-each select="following-sibling::node()">
          <xsl:choose>

             <xsl:when test="self::H">
                <!-- Should be fantastic to exit from the loop! -->
             </xsl:when>

             <xsl:when test="self::I"
                <I>
                   <xsl:copy-of select="@* | node()"/>
                </I>
                <xsl:text>&#13;</xsl:text>
             </xsl:when>

          </xsl:choose>
       </xsl:for-each>
    </xsl:template>

 </xsl:stylesheet>

不幸的是,我能达到的最好的结果就是

代码语言:javascript
复制
<root>
    <H>
       1
       <I>1-1</I>
       <I>1-2</I>
       <I>1-3</I>
       <I>2-1</I>     wrong!
       <I>2-2</I>     wrong!
    </H>
    <H>
       2
       <I>2-1</I>
       <I>2-2</I>
    </H>
 </root>

<I>2-1</I><I>2-2</I>在H1下是错误的。

问题是,当模板copyI找到和H时,我无法逃离它。由于源结构是平面的(都是同级结构),恐怕递归copyI没有帮助。

有什么建议吗?

非常感谢。尼古拉

如何扩展您的解决方案?

托玛拉克,非常感谢你的帮助。实际上,我的需求要复杂一些,而且您的解决方案是不可伸缩的。在我的源代码中,可以选择呈现一个<C>第三层,它以层次结构依赖于<I>

代码语言:javascript
复制
<root>
   <H>1</H>
   <I>1-1</I>
   <C>1-1-1</C>
   <I>1-2</I>
   <C>1-2-1</C>
   <I>1-3</I>
   <H>2</H>
   <I>2-1</I>
   <I>2-2</I>
   <C>2-2-1</C>
</root>

而预期的产出是

代码语言:javascript
复制
<root>
   <H>1
    <I>1-1<C>1-1-1</C></I>
    <I>1-2<C>1-2-1</C></I>
    <I>1-3</I>
   </H>
   <H>2
    <I>2-1</I>
    <I>2-2<C>2-2-1</C></I>
   </H>
</root>

再次感谢尼古拉

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-10-22 15:20:13

这很简单:

代码语言:javascript
复制
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
  exclude-result-prefixes="msxsl"
>
  <xsl:output method="xml" indent="yes" />

  <xsl:template match="root">
    <xsl:copy>
      <xsl:apply-templates select="H" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="H">
    <xsl:variable name="myId" select="generate-id()" />
    <xsl:copy>
      <xsl:copy-of select="text()[normalize-space() != '']" />
      <xsl:copy-of select="
        following-sibling::I[generate-id(preceding-sibling::H[1]) = $myId]
      " />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

对于每个<H>,您需要复制以下<I>元素,这些元素的直接前面的<H>与当前的<H>相同(通过比较generate-id()的结果,在generate-id()中建立节点标识)。

输出:

代码语言:javascript
复制
<root>
  <H>1<I>1-1</I><I>1-2</I><I>1-3</I></H>
  <H>2<I>2-1</I><I>2-2</I></H>
</root>

缩进取决于您使用的XSLT处理程序,但是由于不重要的空格是.无足轻重,你不应该太担心这个。

如果您喜欢XSL键,您可以通过使用XSL键来实现相同的目标:

代码语言:javascript
复制
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
  exclude-result-prefixes="msxsl"
>
  <xsl:output method="xml" indent="yes" />

  <xsl:key name="kI" match="I" use="generate-id(preceding-sibling::H[1])" />

  <xsl:template match="root">
    <xsl:copy>
      <xsl:apply-templates select="H" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="H">
    <xsl:copy>
      <xsl:copy-of select="text()[normalize-space() != '']" />
      <xsl:copy-of select="key('kI', generate-id())" />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

该键可以提高大输入文档的性能。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26510737

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档