Как использовать для каждого элемента в качестве параметра шаблона

#json #xslt

#json #xslt

Вопрос:

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

У меня есть java-приложение, которое возвращает массив JSON, моя цель — проанализировать этот результат в строковом формате, который будет использоваться в другом приложении «C», единственная возможная связь между этими двумя приложениями — строковый формат.

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

Мой XML- это :

 <?xml version="1.0" encoding="UTF-8"?>
<input>[{"media_key":"1-1UL-12528","media_value":"10 RUE DES TRELISSAC","media_type":"Courrier"},{"media_key":"2-1UL-12528","media_value":"0614263770","media_type":"SMS"}]</input>
  

и мой XSL — это :

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

 <xsl:template match="input">
    <output>
        <xsl:call-template name="print-object-values">
            <xsl:with-param name="string" select="."/>
        </xsl:call-template>
    </output>
</xsl:template>

<!-- Recupere la valeur d'une cle json String de type "key":"val" -->
<xsl:template name="get_string_json">
    <xsl:param name = "json" />
    <xsl:param name = "key" />

    <xsl:variable name="needle">
        <xsl:value-of select="concat('amp;quot;', $key, 'amp;quot;:amp;quot;')" />
    </xsl:variable>

    <xsl:value-of select="substring-before(substring-after($json, $needle), 'amp;quot;')" />
</xsl:template>


<xsl:template name="print-object-values">
    <xsl:param name="string"/>
    <xsl:param name="sep_values" select="';'" />

    <xsl:if test="contains($string,'media_key')">
        <xsl:text>|</xsl:text>

        <!-- Partie à modifier en récupérant les valeurs désiré par les fonctions déclarer prècedemment -->
        <xsl:call-template name="get_string_json">
            <xsl:with-param name="json" select="$string" />
            <xsl:with-param name="key" select="'media_key'" />
        </xsl:call-template>
        <xsl:value-of select="$sep_values" />
        <xsl:call-template name="get_string_json">
            <xsl:with-param name="json" select="$string" />
            <xsl:with-param name="key" select="'media_type'" />
        </xsl:call-template>
        <xsl:value-of select="$sep_values" />
        <xsl:call-template name="get_string_json">
            <xsl:with-param name="json" select="$string" />
            <xsl:with-param name="key" select="'media_value'" />
        </xsl:call-template>

        <xsl:call-template name="print-object-values">
            <xsl:with-param name="string" select="substring-after($string,'amp;quot;},{')"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>
  

в моем шаблоне print-object-values я использую print-object-values для получения значения определенного ключа в строке JSON.

Что я хочу сделать, так это вместо жесткого кодирования строки, которую я ищу, есть ли способ реализовать это в переменной в виде map, а затем использовать его в цикле for-each для выполнения get_string_json ?

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

вот пример того, чего я хочу достичь

 <xsl:template match="input">
    <output>
        <xsl:variable name="values">  <!-- declaration of the values to search for -->
            <value>
                <param>media_key</param>
                <param>media_type</param>
                <param>media_value</param>
            </value> 
        </xsl:variable>

        <xsl:call-template name="print-object-values">
            <xsl:with-param name="string" select="."/>
        </xsl:call-template>
    </output>
</xsl:template>

<xsl:template name="get_string_json">
    <xsl:param name = "json" />
    <xsl:param name = "key" />

    <xsl:variable name="needle">
        <xsl:value-of select="concat('amp;quot;', $key, 'amp;quot;:amp;quot;')" />
    </xsl:variable>

    <xsl:value-of select="substring-before(substring-after($json, $needle), 'amp;quot;')" />
</xsl:template>


<xsl:template name="print-object-values">
    <xsl:param name="string"/>
    <xsl:param name="sep_values" select="';'" />

    <xsl:if test="contains($string,'media_key')">
        <xsl:text>|</xsl:text>

        <xsl:for-each select= ><!-- select params in the variable values -->
            <xsl:call-template name="get_string_json">
                <xsl:with-param name="json" select="$string" />
                <xsl:with-param name="key" select="" /><!-- pass the value of the param -->
            </xsl:call-template>
        </xsl:for-each>
        <xsl:call-template name="print-object-values">
            <xsl:with-param name="string" select="substring-after($string,'amp;quot;},{')"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>
  

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

1.XSLT 3 с XPath 3.1 имеет такие функции, как parse-json w3.org/TR/xpath-functions/#func-parse-json таким образом, используя Saxon 9.8 или более позднюю версию, вы можете использовать обычный XSLT / XPath для синтаксического анализа и обработки JSON, не пытаясь написать анализатор JSON на XSLT.

2. я новичок в XSLT, в своем приложении я нашел только, как внедрить XSLT 1.0 в существующий код, я не знаю, смогу ли я так просто переключиться на XSLT 3, достаточно ли изменить версию с 1.0 на 3.0 или мне нужно переписать часть моего кода?

3. Вам нужно использовать процессор XSLT 3, такой как Saxon 9.8 или 9.9, поэтому в мире Java ( mvnrepository.com/artifact/net.sf.saxon/Saxon-HE ) или в .NET ( nuget.org/packages/Saxon-HE ) это просто, поскольку для этих платформ существуют версии Saxon 9.8 или 9.9 с открытым исходным кодом. Вы не показали и не объяснили, как вы используете XSLT, поэтому невозможно сказать, что вам нужно изменить.

4. Прежде всего, спасибо вам, Мартин, за ваши ответы. Мне просто нужно указать, что у меня нет доступа к коду приложения Java, и я ничего не могу изменить, только XSL. Я стажер в компании, которая использует XSL для преобразования HTTP-ответов в строковое значение, а затем отправляет его в приложение на C для дальнейшего использования. JSON находится внутри XML-ответа. Мое решение функционально, я уже тестирую его и работает как шарм, но всегда нужно жестко кодировать значения, которые я ищу внутри шаблона. Что мне нужно, так это метод для перебора массива или переменных XML и для вызова шаблона для каждого элемента

5. Циклы, массивы? Что ж, удачи.

Ответ №1:

ВАЖНО:
Цель этого ответа — рассмотреть только эту часть вашего вопроса:

вместо жесткого кодирования строки, которую я ищу, есть ли способ реализовать это в переменной в виде map, а затем использовать ее в цикле for-each для выполнения get_string_json ?

Я счел необходимым внести некоторые коррективы в другие части вашего XSLT, но я не изучал ваш метод синтаксического анализа JSON.

XSLT 1.0

 <xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />

<!-- declaration of the values to search for -->
<xsl:variable name="keys">  
    <key>media_key</key>
    <key>media_type</key>
    <key>media_value</key>
</xsl:variable>

<xsl:template match="input">
    <output>
        <xsl:call-template name="print-object-values">
            <xsl:with-param name="string" select="."/>
        </xsl:call-template>
    </output>
</xsl:template>

<xsl:template name="print-object-values">
    <xsl:param name="string"/>
    <xsl:param name="separator" select="'amp;quot;},{'" />

    <xsl:variable name="object" select="substring-before(concat($string, $separator), $separator)" />

    <xsl:text>|</xsl:text>

    <!-- HERE IS THE RELEVANT PART -->
    <xsl:for-each select="exsl:node-set($keys)/key">
        <xsl:call-template name="get_string_json">
            <xsl:with-param name="json" select="concat($object, 'amp;quot;')" />
            <xsl:with-param name="key" select="." />
        </xsl:call-template>
        <xsl:if test="position()!=last()">
            <xsl:text>;</xsl:text>
        </xsl:if>
    </xsl:for-each>

    <xsl:if test="contains($string, $separator)">
        <xsl:call-template name="print-object-values">
            <xsl:with-param name="string" select="substring-after($string, $separator)"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

<!-- Recupere la valeur d'une cle json String de type "key":"val" -->
<xsl:template name="get_string_json">
    <xsl:param name = "json" />
    <xsl:param name = "key" />

    <xsl:variable name="needle">
        <xsl:value-of select="concat('amp;quot;', $key, 'amp;quot;:amp;quot;')" />
    </xsl:variable>

    <xsl:value-of select="substring-before(substring-after($json, $needle), 'amp;quot;')" />
</xsl:template>

</xsl:stylesheet>