Как выполнить пересечение в наборе узлов с помощью xpath 2.0 - PullRequest
0 голосов
/ 06 июля 2019

У меня есть два разных набора узлов, которые содержат один или несколько элементов с одинаковыми именами.

Я хочу выбрать эти одноименные элементы, используя операцию пересечения в XPath 2.0 и XPath 1.0.

Это пример кода, который я пробовал.

Ввод:

    <?xml version="1.0" encoding="UTF-8"?>
    <root>
    <child1>
    <a />
    <b />
    <d />
    </child1>
    <child2>
    <c />
    <a />
    <d />
    </child2>
    </root>

Код, который я пробовал

Xpath 1.0:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
    <!-- TODO: Auto-generated template -->
    <xsl:variable name="ns2" select="/root/child2/child::*"/>       
    <xsl:copy-of select="/root/child1/child[.=$ns2]"/>
    </xsl:template>
    </xsl:stylesheet>

Xpath 2.0:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
    <!-- TODO: Auto-generated template -->
    <xsl:variable name="ns1" select="/root/child1/child::*"/>
    <xsl:variable name="ns2" select="/root/child2/child::*"/>       
    <xsl:copy-of select="$ns1 intersect $ns2"/>
    </xsl:template>
    </xsl:stylesheet>

Проблема: получен пустой результат.

Ожидаемый результат:

    <?xml version="1.0" encoding="UTF-8"?>
    <a/>
    <d/>

Пожалуйста, укажите, что мне не хватает.

Я пробовал пересечение операции set для двух разных наборов заметок. Ниже приведен пример кода,

Ответы [ 2 ]

1 голос
/ 06 июля 2019

Вы на самом деле не делаете "пересечение" здесь, потому что все дочерние элементы child1 отличаются от дочерних элементов child2.Тот факт, что два элемента имеют одно и то же имя, не делает их одним и тем же элементом.

То, что вам нужно, выглядит так: элементы под child1 имеют то же имя, что и элемент под child2

Если вы хотите, чтобы ваше решение XSLT 1.0 получало результаты, вам нужно изменить xsl:copy-of на

<xsl:copy-of select="/root/child1/child::*[.=$ns2]"/>

Или это ...

 <xsl:copy-of select="/root/child1/*[.=$ns2]"/>

Однако, это вернет все child1 дочерние элементы, потому что вы проверяете, совпадают ли значения элементов, а не имени.Один из способов сделать это - это ...

<xsl:for-each select="/root/child1/*">
    <xsl:variable name="name" select="local-name()" />
    <xsl:copy-of select=".[$ns2[local-name() = $name]]" />
</xsl:for-each>

В качестве альтернативы определите ключ следующим образом:

<xsl:key name="child2" match="child2/*" use="local-name()" />

Тогда вы можете сделать это ...

<xsl:copy-of select="/root/child1/*[key('child2', local-name())]"/>

В XSLT 2.0 вы могли бы сделать что-то вроде этого ...

<xsl:copy-of select="$ns1[some $name in $ns2/local-name() satisfies $name=local-name()]"/>
0 голосов
/ 06 июля 2019

Не повторяя правильное замечание Тима, но только к проблеме:

XSLT 1.0 (невозможно с одним выражением XPath, если не используется стандартная функция XSLT, такая как current()):

<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="child1/*">
    <xsl:copy-of select="self::*[../../child2/*[name() = name(current())]]"/>
  </xsl:template>
</xsl:stylesheet>

XPath 2.0 :

Использование:

/*/child1/*[name() = /*/child2/*/name()]

Это можно проверить с помощью приведенного ниже преобразования XSLT 2.0, которое оценивает выражение и выводит выбранные узлы:

<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="/">
    <xsl:sequence select=
     "/*/child1/*[name() = /*/child2/*/name()]"/>
  </xsl:template>
</xsl:stylesheet>

При применении к предоставленному документу XML :

<root>
    <child1>
        <a />
        <b />
        <d />
    </child1>
    <child2>
        <c />
        <a />
        <d />
    </child2>
</root>

оба преобразования дают желаемый, правильный результат :

<a/>
<d/>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...