xslt:选择两个节点之间的所有特定节点,但在特定节点处停止

时间:2018-02-23 15:38:41

标签: xml xslt xpath

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

.........

<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>

..........

我需要在标记<p class="dialogo"/>之间和之后选择所有<p class="busta"/>,但如果我找到了<p class="capo"/>,我需要停止... 结果必须是这样的:

<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> 
..........

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

时停止

提前致谢

1 个答案:

答案 0 :(得分:1)

假设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"
    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>

改变

<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> 

进入

<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>

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

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

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

为了举例说明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"
    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>

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