Home > OS >  xslt standardize nested JSON
xslt standardize nested JSON

Time:11-22

I work on a generic XSL to standardize different nested JSON. My sample JSONs

/soccer2.json

{
"position": "main", 
"others": "spiss;sweeper", 
"player": 
  {
    "midtbane": [
      "offensiv-midtbane", 
      "defensiv-midtbane"
    ]
  }
}

/soccer1.json

{
 "position": "main", 
 "others": [
    {
        "wing": "høyreving;venstreving", 
        "fullback": [
              "venstreback", 
              "høyreback"
        ]
    }
  ], 
  "player": [
        {
          "left": "venstre-midtbane", 
          "center": "høyre-midtbane", 
          "right": "sentral-midtbane"
        }
    ]   
  }

My xsl

const myXsl =
  fn.head(xdmp.unquote(
`
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">  
  
    <xsl:template match="/">
        <sport>
            <xsl:if test="exists(position)">
                <positionType>
                  <xsl:copy-of select="position"/>
                </positionType>
            </xsl:if> 
            
        <!--    <xsl:if test="exists(others)">
                <otherPosition>
                  <xsl:copy-of select="others"/>
                </otherPosition>
            </xsl:if>   
-->
 
            <xsl:if test="exists(player)">
                <playerPosition>
                   <xsl:for-each select="player/child::node()">
                     <xsl:element name="{name()}">  
                        <xsl:value-of select="."/>
                     </xsl:element>  
                   </xsl:for-each>
                </playerPosition>
            </xsl:if>            
        </sport>
    </xsl:template>
    
</xsl:transform>
`));
const doc = cts.doc('/soccer2.json')
xdmp.xsltEval(myXsl, doc)

Unexpected output:

/soccer2.json
<sport>
  <positionType>main</positionType>
  <otherPosition>spiss;sweeper</otherPosition>
  <playerPosition>
    <midtbane>["offensiv-midtbane", "defensiv-midtbane"]</midtbane>
  </playerPosition>
</sport>

Expected output:

/soccer2.json
<sport>
  <positionType>main</positionType>
  <otherPosition>spiss;sweeper</otherPosition>
  <playerPosition>
    <midtbane>offensiv-midtbane</midtbane>
    <midtbane>defensiv-midtbane</midtbane>
  </playerPosition>
</sport>

Do I expect this work in XSLT? Thanks in advance for any help!

CodePudding user response:

XSLT 3.0 has the ability to process JSON: earlier versions do not. You don't appear to be making use of the XSLT 3.0 capabilities for handling JSON.

(You've tagged it "marklogic" - perhaps there is something in the ML XSLT processor that would make this work; I wouldn't know about that).

I would expect your code simply to fail saying that the input isn't well-formed XML.

CodePudding user response:

The MarkLogic XSLT implementation, you should be looking at:

const implFlattenJToX=
  fn.head(xdmp.unquote(
`
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xdmp="http://marklogic.com/xdmp"
    xdmp:dialect="1.0-ml" version="2.0">
        
    <xsl:template name="sport">        
        <xsl:variable name="v_position" select="position"/>
        <xsl:variable name="v_player" select="player"/>        
        <sport>
            <xsl:if test="exists(position)">
                <positionType>
                    <xsl:copy-of select="position"/>
                </positionType>
            </xsl:if>            
            <xsl:if test="exists($v_player)">
                <playerPosition>
                    <xsl:for-each select="/player">
                        <xsl:call-template name="flattenJson"/>
                    </xsl:for-each>
                </playerPosition>
            </xsl:if>      
        </sport>
    </xsl:template>
    
    <xsl:template name="flattenJson">
        <xsl:for-each select="*"> 
            <xsl:choose>
                <xsl:when test="array-node()|object-node()">
                    <xsl:for-each select="./node()">
                        <xsl:apply-templates select="xdmp:from-json(.)"/>
                    </xsl:for-each>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:element name="{(name(.))}">
                        <xsl:value-of select="."/>
                    </xsl:element>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each> 
    </xsl:template>     
    
    <xsl:template match="/">
        <xsl:call-template name="sport"/>
    </xsl:template>
    
</xsl:transform>

`));
  • Related