选择前面的元素,直到找到要停止的元素(XSLT 1.0)

时间:2018-03-09 23:39:13

标签: xslt xslt-1.0

我想在鸟类之前选择一个先于鸟类的元素,但不要选择鸟类或狗类。而且,我不知道这些元素是什么。它们可能与示例XML中的不同。而且,我想在选择变量时这样做。

输入XML:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <a>cat</a>
  <a>dog</a>
  <a>dog</a>
  <a>cat</a>
  <a>snake</a>
  <a>cat</a>
  <a>cat</a>
  <a>bird</a>
  <a>dog</a>
  <a>cat</a>
</root>

所需的输出XML:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <a>cat</a>
  <a>snake</a>
  <a>cat</a>
  <a>cat</a>
</root>

XSLT:

<?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:variable name="nodes">
      <xsl:copy-of select="//a"/>
    </xsl:variable>

    <xsl:variable name="nodeList" select="msxsl:node-set($nodes)"/>

    <!-- I want to select the a elements that precede bird until I hit dog, but not select the bird or dog. 
          And, I don't know what the elements are. They could be different than in the sample XML. 
          And, I want to do it in the select of the variable below.
    -->
    <xsl:variable name="subsetOfNodeList" select="$nodeList/a[.='bird']/preceding-sibling::a[. >> $nodeList/a[.='bird']/preceding-sibling::a[.='dog'][1]]"/>

    <xsl:template match="root">
      <xsl:copy>
        <xsl:copy-of select="$subsetOfNodeList"/>
      </xsl:copy>
    </xsl:template> 

</xsl:stylesheet>

2 个答案:

答案 0 :(得分:1)

鉴于XSLT 1,我认为您可以选择bird的前一个兄弟并且相交(记住节点集n1n2的交集与$n1[count(. | $n2) = count($n2)]完成)dog之后的任何内容,这里有一个例子,它还使用一个键来识别dog之后的内容:

  <xsl:key name="fol" match="a[not(. = 'dog')]" use="generate-id(preceding-sibling::a[. = 'dog'][1])"/>

  <xsl:template match="root">
      <xsl:variable name="bird" select="a[. = 'bird']"/>
      <xsl:variable name="prec-dog" select="$bird/preceding-sibling::a[. = 'dog'][1]"/>
      <xsl:variable name="fol-dog" select="key('fol', generate-id($prec-dog))"/>
      <xsl:variable name="prec-siblings" select="$bird/preceding-sibling::a[not(. = 'dog')]"/>
      <xsl:variable name="intersect" select="$prec-siblings[count((. | $fol-dog)) = count($fol-dog)]"/>
      <xsl:copy>
          <xsl:copy-of select="$intersect"/>
      </xsl:copy>
  </xsl:template>

输入的https://xsltfiddle.liberty-development.net/eiQZDbr/2

<root>
  <a id="c1">cat</a>
  <a id="d1">dog</a>
  <a id="d2">dog</a>
  <a id="c3">cat</a>
  <a id="s1">snake</a>
  <a id="c4">cat</a>
  <a id="c5">cat</a>
  <a>bird</a>
  <a>dog</a>
  <a>cat</a>
</root>

我得到了结果

<root>
  <a id="c3">cat</a>
  <a id="s1">snake</a>
  <a id="c4">cat</a>
  <a id="c5">cat</a>
</root>

答案 1 :(得分:1)

可能的解决方案之一是制作&#34; initial&#34;专用电话 模板(让我们称之为打印),将最后一个元素传递给它 打印,即 bird 元素的第一个前一个兄弟(我假设 这样的 bird 元素只有一个。

此模板:

  • 检查传递的参数是否包含其他内容 dog (实际上是做任何事情的条件)。如果是这种情况,那么:
    • 对自己进行递归调用,将其传递给前面的第一个 论证元素的兄弟。
    • 打印作为参数传递的元素。

所以整个脚本可能如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" encoding="UTF-8" indent="yes" />

  <xsl:template name="print">
    <xsl:param name="xx"/>
    <xsl:if test="$xx/text() != 'dog'">
      <xsl:call-template name="print">
        <xsl:with-param name="xx" select="$xx/preceding-sibling::*[1]"/>
      </xsl:call-template>
      <xsl:copy-of select="$xx"/>
    </xsl:if>
  </xsl:template>

  <xsl:template match="root">
    <xsl:copy>
      <xsl:call-template name="print">
        <xsl:with-param name="xx" select="a[text() = 'bird']/preceding-sibling::*[1]"/>
      </xsl:call-template>
    </xsl:copy>
  </xsl:template>
</xsl:transform>

有关工作示例,请参阅http://xsltfiddle.liberty-development.net/gWcDMet