Получение значений из узлов, когда сам XPath является текстом внутри узла - PullRequest
1 голос
/ 13 апреля 2011

Простая проблема: у меня есть XML-файл, подобный этому:

<Locations>
    <Location>/Simulation/@ID</Location>
    <Location>/Simulation/Loans</Location>
    <Location>/Simulation/Assets</Location>
    <Location>/Simulation/BankAssets</Location>
    <Location>/Simulation/RealEstates</Location>
</Locations>

У меня также есть второй XML-файл, содержащий данные, которые соответствуют этим узлам XPath.И мне нужно создать XSLT 1.0 без каких-либо сценариев, которые могут преобразовать этот файл данных, чтобы просто создать список данных, который соответствует этим узлам.Примерно так:

<Data>
    <Item Node="/Simulation/@ID">
        <Value>1</Value>
        <Value>2</Value>
        <Value>3</Value>
    </Item>
    <Item Node="/Simulation/Loans">
        <Value>1024</Value>
        <Value>555</Value>
        <Value>0</Value>
    </Item>
</Data>

Количество узлов Value на элемент неважно.Также не важна связь между ценностями разных предметов.По сути, таблица стилей предназначена для сбора простых статистических данных, которые будут суммироваться, усредняться и многое другое.Список местоположений может сильно отличаться, в зависимости от того, что хочет пользователь.В этом примере приведены только некоторые данные подделки.

Вопрос: как собрать эту информацию?

1 Ответ

2 голосов
/ 13 апреля 2011

На самом деле есть два способа сделать это: один - выполнить двухфазное преобразование, а другой - использовать функцию расширения evaluate.

Двухфазное преобразование

Сначала вам нужно сгенерировать правильный XSL на основе вашего списка Locations. Это может выглядеть так:

<xsl:template match="/">
    <Data>
        <Item Node="/Simulation/@ID">
            <xsl:apply-templates select="/Simulation/@ID"/>
        </Item>
        <Item Node="/Simulation/Loans">
            <xsl:apply-templates select="/Simulation/Loans"/>
        </Item>

        <!-- ... and so on ... -->

    </Data>
</xsl:template>

<xsl:template match="node()|@*">
    <Value>
        <xsl:value-of select="."/>
    </Value>
</xsl:template>

Полагаю, у вас нет особых проблем с созданием преобразования, которое будет генерировать этот вывод на основе вашего файла определения XPath, поскольку шаблон довольно прост.

Следующим шагом является применение сгенерированного преобразования к вашему исходному файлу. Вы можете объединить эти два шага в маленькую трубу и получить желаемый результат.

Использование функции расширения

Библиотека EXSLT содержит функцию расширения под названием оценивать , которая помогает в таких случаях, как ваш. Он поддерживается трансформером Xalan из коробки, но не Saxon, насколько я знаю. Однако существует серьезная проблема с этой функцией - начиная с версии 2.7 Xalan существует ошибка , которая препятствует выполнению нескольких оценок. К сожалению, приведенная ниже таблица стилей затронута, когда я попытался ее запустить Предложение будет изменить версию Xalan на 2.6, если это возможно. Тем не менее, вот таблица стилей, которая будет делать то, что вы хотите, без дополнительной фазы генерации.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:dyn="http://exslt.org/dynamic" extension-element-prefixes="dyn">

    <xsl:variable name="locations" select="document('xpath.xml')/Locations"/>
    <xsl:variable name="root" select="/"/>

    <xsl:template match="/">
        <Data>
            <xsl:for-each select="$locations/Location">
                <Item Node="{.}">
                    <xsl:variable name="currentLocation" select="concat('$root', .)"/>
                    <xsl:apply-templates select="dyn:evaluate($currentLocation)"/>
                </Item>
            </xsl:for-each>
        </Data>
    </xsl:template>

    <xsl:template match="node()|@*">
        <Value>
            <xsl:value-of select="."/>
        </Value>
    </xsl:template>

</xsl:stylesheet>

Предполагается, что документ с определениями Locations находится в одном каталоге и называется xpath.xml. Обновите document() использование функции, если это не так.

...