xslt 在同级节点内移动节点 [英] xslt move node inside sibling node

查看:35
本文介绍了xslt 在同级节点内移动节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

研究了一天的 XSLT,我认输了!

这是我的输入:

<div class="b">b1</div><div class="c">b1c1</div><div class="d">b1d1</div><div class="d">b1d2</div><div class="b">b2</div><div class="c">b2c1</div><div class="d">b2d1</div><div class="d">b2d2</div><div class="d">b2d3</div><div class="b">b3</div><div class="c">b3c1</div><div class="d">b3d1</div>

这是我想要的输出:

<div class="b">b1<div class="c">b1c1</div><div class="d">b1d1</div><div class="d">b1d2</div>

<div class="b">b2<div class="c">b2c1</div><div class="d">b2d1</div><div class="d">b2d2</div><div class="d">b2d3</div>

<div class="b">b3<div class="c">b3c1</div><div class="d">b3d1</div>

这是我正在使用的 xslt:

<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:模板><!-- 覆盖目标元素--><xsl:template match="div[@class='a']"><!-- 复制元素--><xsl:copy><!-- 以及里面的一切--><xsl:copy-of select="@*|node()"/><!-- 移动节点--><xsl:apply-templates select="div[@class='c']"/><xsl:apply-templates select="div[@class='d']"/></xsl:copy></xsl:模板></xsl:stylesheet>

但它给了我错误的输出:

<div class="b">b1</div><div class="c">b1c1</div><div class="d">b1d1</div><div class="d">b1d2</div><div class="b">b2</div><div class="c">b2c1</div><div class="d">b2d1</div><div class="d">b2d2</div><div class="d">b2d3</div><div class="b">b3</div><div class="c">b3c1</div><div class="d">b3d1</div><div class="c">b1c1</div><div class="c">b2c1</div><div class="c">b3c1</div><div class="d">b1d1</div><div class="d">b1d2</div><div class="d">b2d1</div><div class="d">b2d2</div><div class="d">b2d3</div><div class="d">b3d1</div>

我明白为什么它会给我这个输出,但我找不到修改它并获得正确输出的方法.

提前致谢.

拉头发

解决方案

看起来您正在按照前面的第一个b"类对c"和d"类进行分组.要在 XSLT 1.0 中执行此操作,您可以定义一个键来捕获此分组.

<xsl:key name="b" match="div[@class!='b']" use="generate-id(preceding-sibling::div[@class='b'][1])"/>

因此,与其选择模板中与a"类匹配的所有子节点,不如选择b"类

然后,在匹配b"类的模板中,可以使用key获取关联的c"和d"元素

<xsl:copy><xsl:copy-of select="@*"/><xsl:apply-templates select="key('b', generate-id())"/></xsl:copy></xsl:模板>

试试这个 XSLT

<xsl:output omit-xml-declaration="yes" indent="yes"/><xsl:strip-space elements="*"/><xsl:key name="b" match="div[@class!='b']" use="generate-id(preceding-sibling::div[@class='b'][1])"/><xsl:template match="@*|node()"><xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy></xsl:模板><xsl:template match="div[@class='a']"><xsl:copy><xsl:apply-templates select="@*|div[@class='b']"/></xsl:copy></xsl:模板><xsl:template match="div[@class='b']"><xsl:copy><xsl:apply-templates select="@*|node()"/><xsl:apply-templates select="key('b', generate-id())"/></xsl:copy></xsl:模板></xsl:stylesheet>

在 XSLT 2.0 中,您可以使用 xsl:for-each-group 代替

<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:模板><xsl:template match="div[@class='a']"><xsl:copy><xsl:apply-templates select="@*"/><xsl:for-each-group select="div" group-starting-with="div[@class='b']"><xsl:copy><xsl:apply-templates select="@*|node()"/><xsl:apply-templates select="current-group()[position() > 1]"/></xsl:copy></xsl:for-each-group></xsl:copy></xsl:模板></xsl:stylesheet>

After a day's research into XSLT, I am admitting defeat!

This is my input:

<div class="a" >
  <div class="b">b1</div>
  <div class="c">b1c1</div>
  <div class="d">b1d1</div>
  <div class="d">b1d2</div>
  <div class="b">b2</div>
  <div class="c">b2c1</div>
  <div class="d">b2d1</div>
  <div class="d">b2d2</div>
  <div class="d">b2d3</div>
  <div class="b">b3</div>
  <div class="c">b3c1</div>
  <div class="d">b3d1</div>
</div>

And this is the output I would like to get:

<div class="a" >
  <div class="b">b1
    <div class="c">b1c1</div>
    <div class="d">b1d1</div>
    <div class="d">b1d2</div>
  </div>
  <div class="b">b2
    <div class="c">b2c1</div>
    <div class="d">b2d1</div>
    <div class="d">b2d2</div>
    <div class="d">b2d3</div>
  </div>
  <div class="b">b3
    <div class="c">b3c1</div>
    <div class="d">b3d1</div>
  </div>
</div>

This is the xslt that I am using:

<?xml version="1.0"?>
<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="*"/>

 <!-- Identity template, copies everything as is -->
 <xsl:template match="@*|node()">
  <xsl:copy>
   <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
 </xsl:template>

 <!-- Override for target element -->
 <xsl:template match="div[@class='a']">
  <!-- Copy the element -->
  <xsl:copy>
   <!-- And everything inside it -->
   <xsl:copy-of select="@*|node()"/>
   <!-- Move nodes -->
   <xsl:apply-templates select="div[@class='c']"/>
   <xsl:apply-templates select="div[@class='d']"/>
  </xsl:copy>
 </xsl:template>

</xsl:stylesheet>

But it's giving me the wrong output:

<div class="a">
  <div class="b">b1</div>
  <div class="c">b1c1</div>
  <div class="d">b1d1</div>
  <div class="d">b1d2</div>
  <div class="b">b2</div>
  <div class="c">b2c1</div>
  <div class="d">b2d1</div>
  <div class="d">b2d2</div>
  <div class="d">b2d3</div>
  <div class="b">b3</div>
  <div class="c">b3c1</div>
  <div class="d">b3d1</div>
  <div class="c">b1c1</div>
  <div class="c">b2c1</div>
  <div class="c">b3c1</div>
  <div class="d">b1d1</div>
  <div class="d">b1d2</div>
  <div class="d">b2d1</div>
  <div class="d">b2d2</div>
  <div class="d">b2d3</div>
  <div class="d">b3d1</div>
</div>

I understand why it's giving me this output, but I cannot find a way to modify it and get the correct output.

Thank you in advance.

PullingHair

解决方案

It looks like you are grouping the "c" and "d" classes by the first preceding "b" class. To do this in XSLT 1.0, you could define a key to capture this grouping.

<xsl:key name="b" match="div[@class!='b']" use="generate-id(preceding-sibling::div[@class='b'][1])" />

So, rather than selecting all child nodes in the template that matches the "a" class, you just select the "b" ones

<xsl:apply-templates select="div[@class='b']" />

Then, in the template that matches the "b" class, you can use the key to get the associated "c" and "d" elements

<xsl:template match="div[@class='b']">
 <xsl:copy>
  <xsl:copy-of select="@*" />
  <xsl:apply-templates select="key('b', generate-id())" />
 </xsl:copy>
</xsl:template>

Try this XSLT

<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:key name="b" match="div[@class!='b']" use="generate-id(preceding-sibling::div[@class='b'][1])" />

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

 <xsl:template match="div[@class='a']">
  <xsl:copy>
   <xsl:apply-templates select="@*|div[@class='b']" />
  </xsl:copy>
 </xsl:template>

 <xsl:template match="div[@class='b']">
  <xsl:copy>
   <xsl:apply-templates select="@*|node()" />
   <xsl:apply-templates select="key('b', generate-id())" />
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

In XSLT 2.0, you can make use of xsl:for-each-group instead

<xsl:stylesheet version="2.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="div[@class='a']">
  <xsl:copy>
   <xsl:apply-templates select="@*" />
   <xsl:for-each-group select="div" group-starting-with="div[@class='b']">
     <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
      <xsl:apply-templates select="current-group()[position() > 1]" />
     </xsl:copy>
    </xsl:for-each-group>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

这篇关于xslt 在同级节点内移动节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆