Toolbox
Toolbox

Reputation: 2493

Run foreach on parsed JSON nested array

Building a table using parsed JSON file as data input. Each value inside the JSON array should be distributed, meanwhile when running the code both values in the JSON array is injected in the same element xml value.

In the code area where I build the "xsl:element" I can manually swap between following which gives me the array content one at at time, but I don't understand how I would make the code iterate over the array data:

<xsl:value-of select="*[1]"/>
<xsl:value-of select="*[2]"/>

JSON:

<data>
{
  "balance-sheets": {
    "sheet-results": {
      "sales": {"values": [3, 5], "title": "Annual sales summary"},
      "costs": {"values": [7, 9], "title": "Accumulated costs per year"}
    }
  }
}
</data>

XSL:

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

<xsl:transform version="3.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:ix="http://www.example.org/1"
  xmlns:se="http://www.example.org/2"
  expand-text="yes"
>

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

  <!-- Block all data that has no user defined template -->
  <xsl:mode on-no-match="shallow-skip"/>

  <xsl:attribute-set name="base">
    <xsl:attribute name="name">se:{parent::*/@key}</xsl:attribute>
  </xsl:attribute-set>

  <!-- Parse JSON file content to XML map -->
  <xsl:template match="data">
    <store>
      <xsl:apply-templates select="json-to-xml(.)/*"/>
    </store>
  </xsl:template>

  <xsl:template match="*[@key='sheet-results']">

    <table>

        <xsl:for-each select="*">

          <tr>

          <td>
            <xsl:value-of select="*[2]"/>
          </td>

          <xsl:for-each select="*">

            <td>
              <span>

                <xsl:element
                  name="ix:nonFraction"
                  use-attribute-sets="base"
                  >
                  <xsl:value-of select="*"/>
                </xsl:element>
              </span>
            </td>

          </xsl:for-each>

      </tr>

        </xsl:for-each>

    </table>

  </xsl:template>

</xsl:transform>

Result:

<?xml version="1.0" encoding="UTF-8"?>
<store xmlns:ix="http://www.example.org/1" xmlns:se="http://www.example.org/2">
   <table>
      <tr>
         <td>Annual sales summary</td>
         <td>
            <span>
               <ix:nonFraction name="se:sales">3 5</ix:nonFraction>
            </span>
         </td>
         <td>
            <span>
               <ix:nonFraction name="se:sales"/>
            </span>
         </td>
      </tr>
      <tr>
         <td>Accumulated costs per year</td>
         <td>
            <span>
               <ix:nonFraction name="se:costs">7 9</ix:nonFraction>
            </span>
         </td>
         <td>
            <span>
               <ix:nonFraction name="se:costs"/>
            </span>
         </td>
      </tr>
   </table>
</store>

Wanted result:

<?xml version="1.0" encoding="UTF-8"?>
<store xmlns:ix="http://www.example.org/1" xmlns:se="http://www.example.org/2">
   <table>
      <tr>
         <td>Annual sales summary</td>
         <td>
            <span>
               <ix:nonFraction name="se:sales">3</ix:nonFraction>
            </span>
         </td>
         <td>
            <span>
               <ix:nonFraction name="se:sales">5</ix:nonFraction>
            </span>
         </td>
      </tr>
      <tr>
         <td>Accumulated costs per year</td>
         <td>
            <span>
               <ix:nonFraction name="se:costs">7</ix:nonFraction>
            </span>
         </td>
         <td>
            <span>
               <ix:nonFraction name="se:costs">9</ix:nonFraction>
            </span>
         </td>
      </tr>
   </table>
</store>

Upvotes: 0

Views: 397

Answers (1)

michael.hor257k
michael.hor257k

Reputation: 117043

Consider the following simplified example:

XSLT 3.0

<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:js="http://www.w3.org/2005/xpath-functions"
exclude-result-prefixes="js">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="/">
    <table>
        <xsl:for-each select="json-to-xml(data)/js:map/js:map/js:map/js:map">
            <tr>
                <th>
                    <xsl:value-of select="js:string[@key='title']"/>
                </th>
                <xsl:for-each select="js:array[@key='values']/js:number">
                    <td>
                        <xsl:value-of select="."/>
                    </td>
                </xsl:for-each>
            </tr>
        </xsl:for-each>
    </table>
</xsl:template>

</xsl:stylesheet>

Applied to your input example, this will return:

Result

<?xml version="1.0" encoding="UTF-8"?>
<table>
   <tr>
      <th>Annual sales summary</th>
      <td>3</td>
      <td>5</td>
   </tr>
   <tr>
      <th>Accumulated costs per year</th>
      <td>7</td>
      <td>9</td>
   </tr>
</table>

Upvotes: 1

Related Questions