Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

auto creating xml elements using XSLT

Tags:

xml

xslt

xpath

I would like to automate the elements based on input file expression.

My input file looks like

<?xml version="1.0" encoding="UTF-8"?>
<mappings>
    <mapping inputContext="InputRoot" outputContext="outputRoot">
        <input>InputParent/InputChild/InputSubChild</input>
        <output>OutputParent/OPChild</output>
    </mapping>
</mappings>

Based on above XML I had created the below XSLT

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns="http://www.testmapping.org/mapping">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">
        <xsl:variable name="outputCtxt" select="mappings/mapping/output"/>
        <xsl:call-template name="contextGenerator">
            <xsl:with-param name="contextPath" select="$outputCtxt"/>
        </xsl:call-template>
    </xsl:template>
    <xsl:template name="contextGenerator">
        <xsl:param name="contextPath" as="xs:string?"/>
        <xsl:variable name="currentContext" select="substring-before($contextPath,'/')"/>
        <xsl:variable name="subContext" select="substring-after($contextPath,'/')"/>
        <xsl:element name="{$currentContext}">
            <xsl:call-template name="contextGenerator">
                <xsl:with-param name="contextPath" select="$subContext"/>
            </xsl:call-template>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

I am expecting the output with below format

<outputRoot>
   <OutputParent>
      <OPChild></OPChild>
   </OutputParent>
</outputRoot>

when I am trying to transform based on the input i am ending up with Expected QName error. Can I have the suggestions to address this issue.

like image 986
Laxmikanth Samudrala Avatar asked Jan 24 '26 10:01

Laxmikanth Samudrala


1 Answers

The contextGenerator template is not properly splitting and recursing. (There is no / in the argument to contextGenerator on the second call, so the splits fail.)

Adding the following to the template helps show the problem:

<xsl:message>
    [<xsl:value-of select="$currentContext"/>] 
    [<xsl:value-of select="$subContext"/>]
</xsl:message>

Output:

[OutputParent] 
[OPChild]
[] 
[]

The following replacement template produces the correct output:

<xsl:template name="contextGenerator">
    <xsl:param name="contextPath" as="xs:string?"/>
    <xsl:choose>
        <xsl:when test="contains($contextPath, '/')">
            <xsl:element name="{substring-before($contextPath, '/')}">
                <xsl:variable name="subContext" 
                              select="substring-after($contextPath, '/')"/>
                <xsl:if test="$subContext">
                    <xsl:call-template name="contextGenerator">
                        <xsl:with-param name="contextPath" select="$subContext"/>
                    </xsl:call-template>
                </xsl:if>
            </xsl:element>
        </xsl:when>
        <xsl:otherwise>
            <xsl:element name="{$contextPath}"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

Result:

<OutputParent>
   <OPChild/>
</OutputParent>
like image 81
Wayne Avatar answered Jan 26 '26 04:01

Wayne