Обновление переменных в XSL - PullRequest
1 голос
/ 04 мая 2010

Есть ли способ в XSL обновить глобальную переменную?

Я хочу проверить, какие элементы я уже преобразовал, и действовать соответственно. Это потребовало бы, чтобы я как-то добавил имена элементов в какой-то список и обновлял его каждый раз, когда преобразуется новый элемент.

Но поскольку xsl:variable не является "переменной" в том смысле, в котором можно было бы ожидать, я не могу добавить что-либо к нему, как только оно будет определено.

У меня есть несколько включенных файлов данных, поэтому использование функций xsl, которые знают только текущий набор узлов, не поможет.

== Редактировать ==

Вот так выглядит моя трансформация. Но он будет включать в себя файлы, на которые постоянно ссылаются в разных вложенных файлах каждый раз.

<?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" />

    <xsl:template match="@*|node()">
        <xsl:copy>
           <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- include the contents of referenced files -->
    <xsl:template match="reference">
        <xsl:apply-templates select="document(@url)/data/node()" />
    </xsl:template>

</xsl:transform>

И файлы данных будут выглядеть примерно так:

<data>
    <reference url="another_data_file.xml"/>
    ... other stuff ...
</data>

Ответы [ 4 ]

7 голосов
/ 04 мая 2010

XSLT является функциональным языком и не позволяет обновлять переменные. Если вам нужно объединить результаты за несколько шагов, обычный подход заключается в использовании рекурсивного шаблона. Пример:

<xsl:template name="transform-elements">
    <xsl:param name="elements-to-process" select="/.."/>
    <xsl:param name="processed-elements" select="/.."/>
    <xsl:if test="$elements-to-process">
        <xsl:variable name="element" select="$elements-to-process[1]"/>

        <!-- ... Do stuff with $element ...-->

        <!-- Recursively invoke template for remaining elements -->
        <xsl:call-template name="transform-elements">
            <xsl:with-param name="elements-to-process" 
                            select="$elements-to-process[position() != 1]"/>
            <xsl:with-param name="processed-elements" 
                            select="$processed-elements|$element"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>
1 голос
/ 04 мая 2010

Если ваши входные данные распределены по нескольким документам, было бы неплохо разделить процесс преобразования на несколько этапов.

Добавить преобразование предварительной обработки, которое вытягивает соответствующие разделы из входных документов в один промежуточный документ. Этот документ может быть преобразован с помощью простого XSLT, и вы можете не столкнуться с проблемами, с которыми сталкиваетесь в настоящее время.

1 голос
/ 04 мая 2010

К сожалению, прямого пути нет, переменные XSL назначаются только один раз, но их можно назначить условно.

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

Таким образом, вы не можете обрабатывать вещи, которые уже были преобразованы, так как они уже завершены.

Посмотрите, как используются xsl: Key и xsl: for-each, это позволит вам упорядочить преобразуемые вами узлы.

Цитировать из w3schools, используя этот XML:

<persons>
  <person name="Tarzan" id="050676"/>
  <person name="Donald" id="070754"/>
  <person name="Dolly" id="231256"/>
</persons> 

А это XSL:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:key name="preg" match="person" use="@id"/>

<xsl:template match="/">
  <html>
  <body>
  <xsl:for-each select="key('preg','050676')">
    <p>
    Id: <xsl:value-of select="@id"/><br />
    Name: <xsl:value-of select="@name"/>
    </p>
  </xsl:for-each>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet> 

Найдет человека с идентификатором «050676». Возможно, использование этого метода с более определенным ключом даст вам необходимую структуру?

0 голосов
/ 04 мая 2010

Я не уверен насчет размера документов, которые вы пытаетесь проанализировать, но в качестве решения для относительно небольших XML-документов вы можете вывести результат в переменную и применив функцию расширения node-set (из exslt, или msxsl и т. д.) применяет преобразование к содержимому переменной, исключая повторяющиеся узлы, как если бы вы обрабатывали один XML-документ.

...