xslt:选择两个节点之间的所有特定节点但在特定节点处停止 [英] xslt: select all specific node between two nodes but stop at specific node

查看:31
本文介绍了xslt:选择两个节点之间的所有特定节点但在特定节点处停止的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须为两个节点之间的所有特定节点选择和应用模板,但在特定节点处停止.....例如在此代码中:

........<p class="capo">1</p><p class="busta">prima</p><p class="dialogo1">数据</p><p class="dialogo2">数据</p><p class="dialogo3">数据</p><p class="busta">seconda:</p><p class="dialogo4">数据</p><p class="dialogo5">数据</p><p class="capo">2</p><p class="capo">3</p><p class="dialogo6">数据</p><p class="capo">4</p><p class="busta">terza:</p>.....

我需要选择标签 <p class="busta"/> 之间和之后的所有 <p class="dialogo"/>,但是如果我发现 <p class="capo"/> 我需要停下来...结果一定是这样的:

<p class="dialogo1">数据</p><p class="dialogo2">数据</p><p class="dialogo3">数据</p></busta><胸围><p class="dialogo4">数据</p><p class="dialogo5">数据</p></busta>.....

"template match="p[@class='busta']" 我正在使用以下代码,但在找到变调夹并捕获对话 6 "select="时选择不会停止以下兄弟:: p[@class='busta'] [generate-id(preceding-sibling::p[@class='busta'][1]) = generate-id(current())]"/>"

提前致谢

解决方案

假设 XSLT 2 或 3 这是一本教科书使用 for-each-group group-starting-with="p[@class = 'busta']" 分别为group-ending-with="p[@class = 'capo']":

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"xmlns:xs="http://www.w3.org/2001/XMLSchema"排除结果前缀=xs"版本=3.0"><xsl:mode on-no-match="shallow-copy"/><xsl:output method="xml" indent="yes"/><xsl:template match="body"><xsl:copy><xsl:for-each-group select="*" group-starting-with="p[@class = 'busta']"><xsl:if test="self::p[@class = 'busta']"><胸围><xsl:for-each-group select="current-group()[position() gt 1]" group-ending-with="p[@class = 'capo']"><xsl:if test="position() eq 1"><xsl:apply-templates select="current-group()[not(self::p[@class = 'capo'])]"/></xsl:if></xsl:for-each-group></busta></xsl:if></xsl:for-each-group></xsl:copy></xsl:模板></xsl:stylesheet>

改变了

<p class="capo">1</p><p class="busta">prima</p><p class="dialogo1">数据</p><p class="dialogo2">数据</p><p class="dialogo3">数据</p><p class="busta">seconda:</p><p class="dialogo4">数据</p><p class="dialogo5">数据</p><p class="capo">2</p><p class="capo">3</p><p class="dialogo6">数据</p><p class="capo">4</p><p class="busta">terza:</p>

进入

<胸围><p class="dialogo1">数据</p><p class="dialogo2">数据</p><p class="dialogo3">数据</p></busta><胸围><p class="dialogo4">数据</p><p class="dialogo5">数据</p></busta><busta/>

请参阅 https://xsltfiddle.liberty-development.net/6qM2e2h.>

对于 XSLT 2,您需要将 xsl:mode 拼写为身份转换模板

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

举个例子,其中 p 元素不是输入元素的子元素,而是作为参数作为元素节点序列传入,下面是它的外观(https://xsltfiddle.liberty-development.net/6qM2e2h/1):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"xmlns:xs="http://www.w3.org/2001/XMLSchema"排除结果前缀=xs"版本=3.0"><xsl:mode on-no-match="shallow-copy"/><xsl:output method="xml" indent="yes"/><xsl:param name="paragraphs" as="element()*"><p class="capo">1</p><p class="busta">prima</p><p class="dialogo1">数据</p><p class="dialogo2">数据</p><p class="dialogo3">数据</p><p class="busta">seconda:</p><p class="dialogo4">数据</p><p class="dialogo5">数据</p><p class="capo">2</p><p class="capo">3</p><p class="dialogo6">数据</p><p class="capo">4</p><p class="busta">terza:</p></xsl:param><xsl:template match="/"><xsl:for-each-group select="$paragraphs" group-starting-with="p[@class = 'busta']"><xsl:if test="self::p[@class = 'busta']"><胸围><xsl:for-each-group select="current-group()[position() gt 1]" group-ending-with="p[@class = 'capo']"><xsl:if test="position() eq 1"><xsl:apply-templates select="current-group()[not(self::p[@class = 'capo'])]"/></xsl:if></xsl:for-each-group></busta></xsl:if></xsl:for-each-group></xsl:模板></xsl:stylesheet>

因此,您使用 for-each-group 的位置、方式和输入选择取决于您,这不取决于模板匹配.您可以编写一个模板或函数,将 p 元素序列作为输入参数,并将 for-each-group 放入模板或函数体中.

I have to select and apply templates for all specific node between two nodes but stop at specific node..... for example in this code:

.........

<p class="capo">1</p>
<p class="busta">prima</p>
<p class="dialogo1">dati</p>
<p class="dialogo2">dati</p>
<p class="dialogo3">dati</p>
<p class="busta">seconda:</p>
<p class="dialogo4">dati</p>
<p class="dialogo5">dati</p>
<p class="capo">2</p>
<p class="capo">3</p>
<p class="dialogo6">dati</p>
<p class="capo">4</p>
<p class="busta">terza:</p>

..........

I need to select all <p class="dialogo"/> between and after tag <p class="busta"/>, but if I found a <p class="capo"/> I need to stop... The result must be like this:

<busta>
  <p class="dialogo1">dati</p>
  <p class="dialogo2">dati</p>
  <p class="dialogo3">dati</p>
</busta>
<busta>
  <p class="dialogo4">dati</p>
  <p class="dialogo5">dati</p>
</busta> 
..........

In "template match="p[@class='busta']" I am using following code but selection dont stop when find capo and catch also dialogo 6 "select="following-sibling::p[@class='busta'] [generate-id(preceding-sibling::p[@class='busta'][1]) = generate-id(current())]"/>"

Thanks in advance

解决方案

Assuming XSLT 2 or 3 this is a text book use of for-each-group group-starting-with="p[@class = 'busta']" respectively group-ending-with="p[@class = 'capo']":

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:output method="xml" indent="yes" />

  <xsl:template match="body">
      <xsl:copy>
          <xsl:for-each-group select="*" group-starting-with="p[@class = 'busta']">
              <xsl:if test="self::p[@class = 'busta']">
                  <busta>
                    <xsl:for-each-group select="current-group()[position() gt 1]" group-ending-with="p[@class = 'capo']">
                        <xsl:if test="position() eq 1">
                            <xsl:apply-templates select="current-group()[not(self::p[@class = 'capo'])]"/>
                        </xsl:if>
                    </xsl:for-each-group>
                  </busta>                  
              </xsl:if>
          </xsl:for-each-group>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

That transforms

<body>
<p class="capo">1</p>
<p class="busta">prima</p>
<p class="dialogo1">dati</p>
<p class="dialogo2">dati</p>
<p class="dialogo3">dati</p>
<p class="busta">seconda:</p>
<p class="dialogo4">dati</p>
<p class="dialogo5">dati</p>
<p class="capo">2</p>
<p class="capo">3</p>
<p class="dialogo6">dati</p>
<p class="capo">4</p>
<p class="busta">terza:</p>
</body> 

into

<body>
   <busta>
      <p class="dialogo1">dati</p>
      <p class="dialogo2">dati</p>
      <p class="dialogo3">dati</p>
   </busta>
   <busta>
      <p class="dialogo4">dati</p>
      <p class="dialogo5">dati</p>
   </busta>
   <busta/>
</body>

See https://xsltfiddle.liberty-development.net/6qM2e2h.

For XSLT 2 you need to spell out the xsl:mode as the identity transformation template

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

To give you an example where the p elements are not children of an input element but passed in as a parameter as a sequence of element nodes, here is how that would look (https://xsltfiddle.liberty-development.net/6qM2e2h/1):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:output method="xml" indent="yes" />

  <xsl:param name="paragraphs" as="element()*">
        <p class="capo">1</p>
        <p class="busta">prima</p>
        <p class="dialogo1">dati</p>
        <p class="dialogo2">dati</p>
        <p class="dialogo3">dati</p>
        <p class="busta">seconda:</p>
        <p class="dialogo4">dati</p>
        <p class="dialogo5">dati</p>
        <p class="capo">2</p>
        <p class="capo">3</p>
        <p class="dialogo6">dati</p>
        <p class="capo">4</p>
        <p class="busta">terza:</p>
  </xsl:param>

  <xsl:template match="/">
      <xsl:for-each-group select="$paragraphs" group-starting-with="p[@class = 'busta']">
          <xsl:if test="self::p[@class = 'busta']">
              <busta>
                <xsl:for-each-group select="current-group()[position() gt 1]" group-ending-with="p[@class = 'capo']">
                    <xsl:if test="position() eq 1">
                        <xsl:apply-templates select="current-group()[not(self::p[@class = 'capo'])]"/>
                    </xsl:if>
                </xsl:for-each-group>
              </busta>                  
          </xsl:if>
      </xsl:for-each-group>
  </xsl:template>

</xsl:stylesheet>

So where and how and with which input selection you use that for-each-group is up to you, that does not depend on template matching. You could write a template or function taking the sequence of p elements as an input parameter and put the for-each-group into the template or function body.

这篇关于xslt:选择两个节点之间的所有特定节点但在特定节点处停止的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆