#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>