XSLT: конвертировать XML в JSON, создавая группу подузлов - PullRequest
0 голосов
/ 09 апреля 2019

Уже несколько дней пытались выполнить преобразование, чтобы получить файл JSON из XML-документов.Мой xml документ имеет разные уровни подузлов, все примеры, которые я нашел в интернете, не соответствуют моему делу.Вот мой пример xml:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <foo id="1" group="B" />
    <foo id="2" group="A" />
    <foo id="3", group="A">
        <foo id="4" group="A" />
        <foo id="5" group="A">
            <foo id="6" group="A" />
            <foo id="7" group="A" />
            <foo id="8" group="A" />
        </foo>
    </foo>
    <foo id="9" group="A"></foo>
</root>

требуемый JSON:

{
    "B": {
        "id": 1
    },
    "A": {
        "id": 2
    },
    "A": [{
            "id": 4
        },
        {
            "A": [{
                    "id": 6
                },
                {
                    "id": 7
                },
                {
                    "id": 8
                }
            ]
        }
    ],
    "A": {
        "id": 9
    }
}

Имеется в виду, когда у меня есть вложенные элементы <foo>, дочерние элементы группируются с родительским элементом и так далее.

Я попробовал некоторый xsl-код ( см. * и см. * ) и не смог заставить их работать для моего случая.

Ответы [ 3 ]

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

Пожалуйста, проверьте этот код:

    <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
    <xsl:output method="xml" omit-xml-declaration="yes"/>
    <xsl:template match="root">
        <xsl:text>{</xsl:text>
        <xsl:text>&#x0A;</xsl:text>
        <xsl:for-each select="foo">
            <xsl:if test="not(child::foo)">
                    <xsl:text>    "</xsl:text><xsl:value-of select="@group"/><xsl:text>": </xsl:text><xsl:text>{</xsl:text><xsl:text>&#x0A;</xsl:text>
                    <xsl:text>        "id": </xsl:text><xsl:value-of select="@id"/><xsl:text>&#x0A;</xsl:text>
                    <xsl:text>    }</xsl:text>
                <xsl:if test="position()!=last()">
                    <xsl:text>,</xsl:text>
                </xsl:if>
                <xsl:text>&#x0A;</xsl:text>
            </xsl:if>
                    <xsl:for-each select="foo">
                        <xsl:if test="not(child::foo)">
                            <xsl:text>    "</xsl:text><xsl:value-of select="@group"/><xsl:text>": </xsl:text><xsl:if test="parent::foo"><xsl:text>[</xsl:text></xsl:if><xsl:text>{</xsl:text><xsl:text>&#x0A;</xsl:text>
                        <xsl:text>            "id": </xsl:text><xsl:value-of select="@id"/><xsl:text>&#x0A;</xsl:text>
                            <xsl:text>        },</xsl:text><xsl:text>&#x0A;</xsl:text>
                            <xsl:text>        {</xsl:text><xsl:text>&#x0A;</xsl:text>
                            <xsl:text>        "</xsl:text><xsl:value-of select="@group"/><xsl:text>": </xsl:text><xsl:text>[</xsl:text><xsl:text>&#x0A;</xsl:text>
                        </xsl:if>

                           <!-- <xsl:text>        "</xsl:text><xsl:value-of select="@group"/><xsl:text>": </xsl:text><xsl:text>[{</xsl:text><xsl:text>&#x0A;</xsl:text>-->
                        <xsl:for-each select="foo">
                            <xsl:text>              {</xsl:text><xsl:text>&#x0A;</xsl:text>
                            <xsl:text>                 "id": </xsl:text><xsl:value-of select="@id"/><xsl:text>&#x0A;</xsl:text>
                            <xsl:text>              }</xsl:text>
                            <xsl:if test="position()!=last()">
                                <xsl:text>,</xsl:text>
                            </xsl:if><xsl:text>&#x0A;</xsl:text>
                            <xsl:if test="position()=last()">
                                <xsl:text>       ]</xsl:text><xsl:text>&#x0A;</xsl:text>
                            </xsl:if>
                            <xsl:if test="position()=last()">
                                <xsl:text>   }</xsl:text><xsl:text>&#x0A;</xsl:text>
                            </xsl:if>
                            <xsl:if test="position()=last()">
                                <xsl:text>],</xsl:text><xsl:text>&#x0A;</xsl:text>
                            </xsl:if>
                            <xsl:text>&#x0A;</xsl:text>
                        </xsl:for-each>
                    </xsl:for-each>
        </xsl:for-each>
        <xsl:text>}</xsl:text>
    </xsl:template>

</xsl:stylesheet>
0 голосов
/ 09 апреля 2019

Не совсем ясно, какой результат вы хотите получить, поскольку требуемый «JSON» имеет дублированные свойства, если есть различные элементы foo group="A", но в целом при генерации XML в JSON вы можете использовать XSLT 3 с поддержкой карт и массивов XPath 3.1(https://www.w3.org/TR/xpath-31/#id-maps-and-arrays) и метод вывода json или функция xml-to-json (https://www.w3.org/TR/xslt-30/#json, https://www.w3.org/TR/xslt-30/#func-xml-to-json),, так что у вас есть два способа создания JSON и его вывода, вы можете преобразовать либоваш XML напрямую в XPath 3.1 отображает / сериализует и сериализует их с <xsl:output method="json"/>, или вы можете использовать обычную обработку XSLT для преобразования вашего входного XML в представление XML JSON, которое ожидает функция xml-to-json, и применить его для получения JSON в виде текста.

Вот пример первого подхода:

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

  <xsl:mode on-no-match="shallow-skip"/>
  <xsl:strip-space elements="*"/>

  <xsl:output method="json" indent="yes"/>

  <xsl:template match="*[*]">
      <xsl:map>
          <xsl:for-each-group select="foo" group-by="@group">
              <xsl:map-entry key="string(current-grouping-key())">
                  <xsl:choose>
                      <xsl:when test="not(tail(current-group()))">
                          <xsl:apply-templates select="current-group()"/>
                      </xsl:when>
                      <xsl:otherwise>
                          <xsl:variable name="group-transform" as="map(*)*">
                              <xsl:apply-templates select="current-group()"/>
                          </xsl:variable>
                          <xsl:sequence select="array { $group-transform }"/>
                      </xsl:otherwise>
                  </xsl:choose>
              </xsl:map-entry>
          </xsl:for-each-group>
      </xsl:map>
  </xsl:template>


  <xsl:template match="*[not(*)]">
      <xsl:sequence select="map { 'id' : data(@id) }"/>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty -development.net / 6r5Gh3i

А вот один извторой:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    exclude-result-prefixes="#all"
    xmlns="http://www.w3.org/2005/xpath-functions"
    expand-text="yes"
    version="3.0">

  <xsl:mode on-no-match="shallow-skip"/>
  <xsl:strip-space elements="*"/>

  <xsl:output method="text"/>

  <xsl:variable name="json-xml">
      <xsl:apply-templates/>
  </xsl:variable>

  <xsl:template match="/">
      <xsl:sequence select="xml-to-json($json-xml, map { 'indent' : true() })"/>
  </xsl:template>

  <xsl:template match="*[*]">
      <map>
          <xsl:for-each-group select="foo" group-by="string(@group)">
              <xsl:choose>
                  <xsl:when test="not(tail(current-group()))">
                      <map key="{current-grouping-key()}">
                          <string key="id">{@id}</string>
                      </map>
                  </xsl:when>
                  <xsl:otherwise>
                      <array key="{current-grouping-key()}">
                          <xsl:apply-templates select="current-group()"/>
                      </array>
                  </xsl:otherwise>
              </xsl:choose>
          </xsl:for-each-group>          
      </map>
  </xsl:template>

  <xsl:template match="*[not(*)]">
      <map>
          <string key="id">{@id}</string>
      </map>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty -development.net / 6r5Gh3i / 5

XSLT 3 доступен с использованием Saxon 9.8 или 9.9 HE для платформы Java на Sourceforgeи мавен https://mvnrepository.com/artifact/net.sf.saxon/Saxon-HE/9.9.1-2 идля платформы .NET на NuGet https://www.nuget.org/packages/Saxon-HE/.

0 голосов
/ 09 апреля 2019
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
    <xsl:strip-space elements="*"/>
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="root">
        <xsl:text>{</xsl:text>
        <xsl:apply-templates select="//foo"/>
        <xsl:text>}</xsl:text>
    </xsl:template>
    <xsl:template match="//foo">
        <xsl:choose>
            <xsl:when test=" count(ancestor::foo) = 1 and child::foo"/>
            <xsl:when test="foo[child::foo]"/>
            <xsl:otherwise>
                <xsl:text>&quot;</xsl:text><xsl:value-of select="@group"/><xsl:text>&quot;</xsl:text>:<xsl:text> {&#x0A;</xsl:text>
                <xsl:text>      &quot;</xsl:text><xsl:value-of select="@id/name()"/><xsl:text>&quot;</xsl:text>:<xsl:value-of select=" concat(' ',@id)"/>
                <xsl:text>&#x0A; },</xsl:text>
            </xsl:otherwise>
        </xsl:choose>     
    </xsl:template>    
</xsl:stylesheet>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...