Как найти отдельные узлы в XML с XPath 1.0, когда мне нужно учитывать содержимое двух узлов xml - PullRequest
2 голосов
/ 27 июня 2019

Это мой первый вопрос здесь.

Я пытаюсь создать xslt, который преобразует XML в текст. Мне нужно найти отдельный список конкатенации LANG и OFFICEID , который затем можно использовать в xsl: for-each loop

Я создал минимальную версию XML, с которой я работаю

    <docinfo>
        <printfile customer="Migrol">
            <envelope postagetype="A">
                <index name="LANG" value="G"/>
                <index name="OFFICEID" value="500"/>
            </envelope>
            <envelope postagetype="A">
                <index name="LANG" value="F"/>
                <index name="OFFICEID" value="500"/>
            </envelope>
            <envelope postagetype="A">
                <index name="LANG" value="G"/>
                <index name="OFFICEID" value="500"/>
            </envelope>
            <envelope postagetype="A">
                <index name="LANG" value="I"/>
                <index name="OFFICEID" value="300"/>
            </envelope>
            <envelope postagetype="A">
                <index name="LANG" value="G"/>
                <index name="OFFICEID" value="100"/>
            </envelope>
            <envelope postagetype="A">
                <index name="LANG" value="G"/>
                <index name="OFFICEID" value="100"/>
            </envelope>
            <envelope postagetype="A">
                <index name="LANG" value="I"/>
                <index name="OFFICEID" value="300"/>
            </envelope>
            <envelope postagetype="A">
                <index name="LANG" value="G"/>
                <index name="OFFICEID" value="500"/>
            </envelope>
        </printfile>
    </docinfo>

В XPath 2.0 это можно решить с помощью оператора

/docinfo/printfile/distinct-values(envelope/concat(index[@name='OFFICEID']/@value, index[@name='LANG']/@value))

или

/docinfo/printfile/envelope[not(concat(index[@name='OFFICEID']/@value, index[@name='LANG']/@value)=preceding-sibling::envelope/concat(index[@name='OFFICEID']/@value, index[@name='LANG']/@value))]/concat(index[@name='OFFICEID']/@value, index[@name='LANG']/@value)

К сожалению, я не нашел способа добиться этого в XPath 1.0. Функция concat, кажется, доставляет мне неприятности.

Простая версия XSLT, которую я хочу использовать

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

    <xsl:template match="printfile">

        <xsl:for-each select="/docinfo/printfile/envelope[not(concat(index[@name='OFFICEID']/@value, index[@name='LANG']/@value)=preceding-sibling::envelope/concat(index[@name='OFFICEID']/@value, index[@name='LANG']/@value))]">
            <xsl:variable name="OID" select="index[@name='OFFICEID'][1]/@value"/>
            <xsl:variable name="LANG" select="index[@name='LANG'][1]/@value"/>

            <xsl:value-of select="$OID"/>
            <xsl:text> </xsl:text>
            <xsl:value-of select="$LANG"/>

            <xsl:text>&#10;</xsl:text>
        </xsl:for-each>

    </xsl:template>

    <!-- suppress default text -->
    <xsl:template match="text()"/>
</xsl:stylesheet>

Результат должен выглядеть примерно так:

"500 G"
"500 F"
"300 I"
"100 G"

Есть ли у кого-нибудь предложения о том, как этого можно достичь с помощью XSLT и XPath 1.0

1 Ответ

0 голосов
/ 27 июня 2019

Предпочтительный метод извлечения различных значений в XSLT 1.0 - мюнхенская группировка .

В вашем примере вам нужно использовать составной ключ:

XSLT 1.0

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

<xsl:key name="env" match="envelope" use="concat(index[@name='OFFICEID']/@value, index[@name='LANG']/@value)" />

<xsl:template match="/docinfo">
    <xsl:for-each select="printfile/envelope[count(. | key('env', concat(index[@name='OFFICEID']/@value, index[@name='LANG']/@value))[1]) = 1]">
        <xsl:value-of select="index[@name='OFFICEID']/@value"/>
        <xsl:text> </xsl:text>
        <xsl:value-of select="index[@name='LANG']/@value"/>
        <xsl:text>&#10;</xsl:text>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

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

<xsl:key name="env" match="envelope" use="concat(index[@name='OFFICEID']/@value, '|', index[@name='LANG']/@value)" />

для предотвращения ложных срабатываний.

...