Как с помощью XSLT v2.0 проверить, соответствует ли текст всех выбранных узлов некоторым справочным значениям?

Например, я выбираю все узлы H1. Я хочу убедиться, что все они равны «Заголовку» или «Заголовку».

Я пытался создать для этого функцию:

<xsl:function name="is-valid" as="xs:boolean">
    <xsl:param name="seq" as="item()*" />
    <xsl:for-each select="$seq">
            <xsl:if test="not(matches(current()/text(),'The title|A heading'))">
                <!-- ??? -->           
            </xsl:if>
    </xsl:for-each>
</xsl:function>

Я не думаю, что это способ использовать XSLT, но я не могу найти, как это сделать.

Есть подсказка?

1
Flag 18 Апр 2016 в 16:14

2 ответа

Лучший ответ

XSLT 2.0 имеет конструкцию every..satisfies, которая может здесь помочь:

<xsl:function name="e:is-valid" as="xs:boolean">
  <xsl:param name="s" as="item()*" />
  <xsl:value-of select="every $i in $s satisfies $i=('The title', 'A heading')"/>
</xsl:function>

Вот полный пример:

XML

<?xml version="1.0" encoding="UTF-8"?>
<r>
  <h1>Wrong title</h1>
  <h1>The title</h1>
  <h1>A heading</h1>
</r>

XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:e="http://example.com/f">

  <xsl:template match="/">
    <xsl:message>
      <xsl:value-of select="e:is-valid(//h1)"/>
    </xsl:message>
  </xsl:template>

  <xsl:function name="e:is-valid" as="xs:boolean">
    <xsl:param name="s" as="item()*" />
    <xsl:value-of select="every $i in $s satisfies $i=('The title','A heading')"/>
  </xsl:function>

</xsl:stylesheet>
2
kjhughes 19 Апр 2016 в 10:27

Просто используйте это простое выражение XPath - закон двойного отрицания :

not(h1[not(. = ('The title','A heading'))])

В качестве демонстрации, учитывая тот же XML-документ, что и в ответе @kjhughes:

<r>
  <h1>Wrong title</h1>
  <h1>The title</h1>
  <h1>A heading</h1>
</r>

Это преобразование XSLT 2.0:

<xsl:stylesheet version="20"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

  <xsl:template match="/*">
    <xsl:sequence select="not(h1[not(. = ('The title','A heading'))])"/>
  </xsl:template>
</xsl:stylesheet>

Дает желаемый правильный результат:

false

Это можно использовать в XPath 1.0, чтобы определить, все ли строковые значения набора узлов $ns1 находятся среди строковых значений другого набора узлов $ns2:

not(not($ns1[. = $ns2]))

Вот эквивалент XPath 1,0 / XSLT 1.0 решения XSLT 2.0 / XPath 2.0:

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:param name="pValues">
   <v>The title</v>
   <v>A heading</v>
 </xsl:param>

 <xsl:variable name="vValues" select="document('')/*/xsl:param[@name='pValues']/*"/>

  <xsl:template match="/*">
    <xsl:value-of select="not(h1[not(. = $vValues)])"/>
  </xsl:template>
</xsl:stylesheet>
3
Dimitre Novatchev 19 Апр 2016 в 14:19