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

#java #xslt #csv #transformation #xalan

#java #xslt #csv #преобразование #xalan

Вопрос:

Итак, вот проблема, которая беспокоит меня последние несколько дней. Это должно быть довольно просто, но XSLT — это просто такая боль для отладки. Мы используем Xalan 1.0 на Java 1.6

Ввод XML

 <?xml version="1.0" encoding="UTF-8"?>
<rfb2>
    <rfb2_item>
        <VALDATE>2011-10-23</VALDATE>
        <FUND_ID>300</FUND_ID>
        <SEC_ID>34567</SEC_ID>
    </rfb2_item>
    <rfb2_item>
        <VALDATE>2011-1-09</VALDATE>
        <FUND_ID>700</FUND_ID>
        <SEC_ID>13587</SEC_ID>
    </rfb2_item>
    <rfb2_item>
        <VALDATE>2011-3-09</VALDATE>
        <FUND_ID>200</FUND_ID>
        <SEC_ID>999334</SEC_ID>
    </rfb2_item>
<rfb2>
  

Нам нужно преобразовать XML в разделенный запятыми список значений для каждого rfb2_item, чтобы таблица стилей всегда повторяла узлы rfb2_item. Мы используем параметр в таблице стилей, чтобы управлять тем, какие элементы rfb2_item (valdate,fund_id, sec_id) будут выводиться и в каком порядке, например

 <xsl:param name="$outputElements" select="'VALDATE,FUND_ID'"/>
..outputs...

2011-10-23,300
2011-1-09,700
2011-3-09,200



<xsl:param name="$outputElements" select="'SEC_ID'"/>    
..outputs...

34567
13587
999334
  

Особый случай, когда, если $outputElements равен ‘*’, просто выводите элементы в том порядке, в котором они отображаются во входном xml

 <xsl:param name="$outputElements" select="'*'"/>

..outputs...

2011-10-23,300,34567
2011-1-09,700,13587
2011-3-09,200,999334
  

Итак, мой вопрос заключается в том, как нам написать шаблон для создания желаемого результата на основе параметра $ outputElements? Рабочий пример был бы отличным…

Комментарии:

1. Вы забыли задать вопрос. Если только вы не хотите, чтобы кто-то написал полный xslt для вас — что они и сделают.

Ответ №1:

Да, FailedDev прав. Кто-нибудь мог бы написать это за вас:

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

    <xsl:output method="text" />

    <xsl:param name="outputElements" select=" 'FUND_ID,SEC_ID,VALDATE' " />

    <xsl:template match="rfb2_item">

        <xsl:for-each select="*[contains($outputElements, local-name()) or $outputElements = '*']">
            <xsl:sort select="string-length(substring-before($outputElements, local-name(.)))" />
            <xsl:value-of select="text()" />
            <xsl:if test="position() != last()">
                <xsl:text>,</xsl:text>
            </xsl:if>
        </xsl:for-each>
        <xsl:text>amp;#13;amp;#10;</xsl:text>

    </xsl:template>

</xsl:stylesheet>
  

Немного объяснения. xsl:for-each Будет выбран каждый элемент в текущем, rfb2_item для которого локальное имя содержится в outputElements параметре, или для которого outputElements параметр является * (который всегда выдавал бы значение true, если это так). Затем они будут отсортированы на основе длины подстроки, которая идет перед этим локальным именем в outputElements . Поскольку это значение становится выше, когда имя встречается позже в этом параметре, это приводит к упорядочению на основе вашего параметра.

Пример: элемент VALDATE выдаст FUND_ID,SEC_ID для substring-before функции, которая, в свою очередь, выдаст 14 в качестве длины строки. Это больше, чем 8, которые вы получили бы для SEC_ID , что означает, что VALDATE значение упорядочено после SEC_ID .

После xsl:sort мы просто используем xsl:value-of для вывода значения элемента. Возможно, вам захочется обрезать там лишние пробелы. Наконец, мы проверяем, не равна ли позиция последнему узлу в текущем контексте (который является позицией xsl:for-each после сортировки), и если да, выведите запятую. Это позволяет избежать вывода запятой после последнего значения.

Перевод строки, который я вставил с помощью xsl:text , предполагает соглашение Windows / DOS. Удалите amp;#13; , если файл должен использовать только символы новой строки для разрывов строк, вместо возврата каретки новая строка.

Обратите внимание, что это не исключает запятых в вашем выводе CSV! Я оставляю это на ваше усмотрение. Было бы интересно изучить возможность использования функций расширения для делегирования этой задачи Java, если это окажется слишком сложным в XSLT / XPath.

Комментарии:

1. Эй, G_H, это здорово, и это работает. Вы только что сняли большой стресс, спасибо. Я добавил <xsl:элементы с разделительным пространством = «*» /> в верхней части таблицы стилей, чтобы удалить все пробелы. У меня действительно было несколько вопросов. Необходима ли сортировка? И комментарии, которые вы сделали по поводу длины строки, меня беспокоят, нужно ли мне учитывать, что если 2 или более элементов имеют одинаковую длину, как в rfb2_item / E1 и rfb2_item / E2?

2. @RaffiM Сортировка выполняется для того, чтобы убедиться, что поля вывода расположены в порядке, определенном вашим параметром, как я полагаю, было одним из требований. Длина строки, которая проверяется, равна длине подстроки, если это параметр , а не содержимое выводимого элемента. Это уловка, чтобы убедиться, что элементы выводятся в порядке, указанном в параметре. В принципе, имя каждого элемента, который должен быть выведен ( FUND_ID , VALDATE …), выдаст другое число. Эти числа устанавливают порядок на основе заданного параметра.

3. @G_H … это имеет смысл … последний вопрос, мы пытаемся интегрировать ваш код в большую таблицу стилей, и это приводит к странным результатам. Мы знаем, что это работает автономно, но проблема в том, как мы это называем. Если мы вызовем ваш шаблон (используя xsl:call-template) из другого шаблона, который уже сопоставлен с «/ *», что изменится в коде вашего шаблона для получения того же результата?

4. @RaffiM xsl:call-template предназначен для именованных шаблонов. Мой использует сопоставление входных данных. Вам нужно либо изменить мой шаблон на именованный и вызвать его с rfb2_item узлом в качестве контекста, либо использовать xsl:apply-templates с выбором, предназначенным для этих узлов.

Ответ №2:

Иногда в подобных ситуациях стоит рассмотреть возможность генерации или модификации XSLT-кода с использованием XSLT. Таким образом вы можете значительно расширить параметризацию — например, контролировать, какие поля выводятся, как они сортируются, группируются ли они, критерии выбора, для которых выбираются строки, и т.д. И т.п.