Как правильно обобщить данные xml в json, используя XSLT 1.0, без использования жестко закодированных элементов? - PullRequest
1 голос
/ 04 апреля 2019

Я работаю над следующим документом XML, в котором я хочу преобразовать XML в JSON.

<?xml version="1.0" encoding="UTF-8"?>
<DATA>
<CATEGORY>
<COUNT> 5 </COUNT>
</CATEGORY>
<TYPE>
<COUNT> 10 </COUNT>
</TYPE>
<FRUITS>
<NAME>APPLE</NAME>
<FRUIT_COUNT>10</FRUIT_COUNT>
</FRUITS>
<FRUITS>
<NAME>ORANGES</NAME>
<FRUIT_COUNT>20</FRUIT_COUNT>
</FRUITS>
</DATA>

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

{
"CATEGORY":5,
"TYPE": 10,
"FRUITS":{
    "APPLE": 10,
    "ORANGES": 20
}
}

Итак, я написал приведенный ниже XSLT-код для преобразования вышеуказанного XML в JSON.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:template match="/DATA">


<xsl:text>{"CATEGORY":</xsl:text>
<xsl:value-of select="CATEGORY/COUNT"/>
<xsl:text>,</xsl:text>

<xsl:text>"TYPE":</xsl:text>
<xsl:value-of select="TYPE/COUNT"/>
<xsl:text>,</xsl:text>

<xsl:text>
"FRUITS": {
</xsl:text>
<xsl:for-each select="FRUITS">
<xsl:text>"</xsl:text>
<xsl:value-of select="NAME"/>
<xsl:text>":</xsl:text>
<xsl:value-of select="FRUIT_COUNT"/>
<xsl:if test="position()!=last()">,</xsl:if>
</xsl:for-each>
<xsl:text>}}</xsl:text>

</xsl:template>
</xsl:stylesheet>

Приведенный выше XSLT преобразует XML в JSON, как и ожидалось. Однако я не могу обобщить вышеупомянутый XSLT, так что если добавляются новые поля, мне не нужно жестко его кодировать, как я это делал в приведенном выше XSLT. Как правильно обобщить XSLT, чтобы он создавал JSON без жесткого кодирования? Есть ли что-то, что я делаю неправильно, обобщая это?

Обновление:

Я попытался обобщить XSLT для преобразования XML в JSON, используя следующий XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:template match="/DATA">

<xsl:text>{</xsl:text>
<xsl:for-each select="/DATA">
  <xsl:for-each select="*">
    <xsl:text>"</xsl:text><xsl:value-of select="local-name()"/><xsl:text>":</xsl:text><xsl:value-of select="."/>
<xsl:if test="position()!=last()">,</xsl:if>
  </xsl:for-each>  
</xsl:for-each>
<xsl:text>}</xsl:text>
</xsl:template>
</xsl:stylesheet>

Но вывод того, когда я использовал вышеупомянутый XSLT, как показано ниже:

{"CATEGORY":
 5 
,"TYPE":
 10 
,"FRUITS":
APPLE
10
,"FRUITS":
ORANGES
20
}

Как обобщить вложенный JSON так, чтобы я мог получить JSON в правильном формате. В преобразованном JSON после модификации я получаю «ФРУКТЫ» дважды, и это не тот вложенный формат, которого я хотел достичь.

1 Ответ

0 голосов
/ 05 апреля 2019

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

  1. Если дочерний элемент корневого элемента DATA не имеет NAME, выведите элемент как свойство с именем имени элемента и текстовым значением в качестве его значения.
  2. Если дочерний элемент имеет NAME, выведите одно свойство с именем имени элемента, а для всех элементов с одинаковым именем выведите вложенные свойства на основе NAME.

В этом случае вы можете написать XSLT следующим образом:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>

<xsl:template match="DATA" priority="2">
  <xsl:text>{</xsl:text>
    <xsl:apply-templates />
  <xsl:text>}</xsl:text>
</xsl:template>

<xsl:template match="*[not(NAME)]">
  <xsl:text>"</xsl:text>
  <xsl:value-of select="name()" />
  <xsl:text>":</xsl:text>
  <xsl:value-of select="normalize-space()"/>
  <xsl:text>,</xsl:text>
</xsl:template>

<xsl:template match="*[NAME][1]">
  <xsl:text>"</xsl:text>
  <xsl:value-of select="name()" />
  <xsl:text>": {</xsl:text>
  <xsl:for-each select="../*[name() = name(current())]">
    <xsl:text>"</xsl:text>
    <xsl:value-of select="NAME"/>
    <xsl:text>":</xsl:text>
    <xsl:value-of select="*[not(self::NAME)]"/>
    <xsl:if test="position()!=last()">,</xsl:if>
  </xsl:for-each>
  <xsl:text>}</xsl:text>
</xsl:template>

<xsl:template match="*[NAME][position() > 1]" />
</xsl:stylesheet>
...