i am trying to transform one xml into another using an xsl.
change input XML's 'name' attribute's value from 'Code' to 'id'
change input XML's 'name' attribute's value from 'Name' to 'name'
copy all nodes under json:array in outpur xml under json:object as
shown in the output xml
I am able to achieve what i have needed using two separate XSLs and trying to figure how I can merge those two XSLs, can you please review and assist me
xsl1:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:dp="http://www.datapower.com/extensions" xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx" xmlns:date="http://exslt.org/dates-and-times" extension-element-prefixes="dp date">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#name[.='Name']">
<xsl:attribute name="name"><xsl:value-of select="'name'"/></xsl:attribute>
</xsl:template>
<xsl:template match="#name[.='Code']">
<xsl:attribute name="name"><xsl:value-of select="'id'"/></xsl:attribute>
</xsl:template>
<xsl:template match="#name[.='SimpleCarrier']">
<xsl:variable name="carrierType">
<xsl:value-of select="'airlines'"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$carrierType='airlines'">
<xsl:attribute name="name"><xsl:value-of select="'airlines'"/></xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="name"><xsl:value-of select="'SimpleCarrierNotUpdated'"/></xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
xsl2:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:dp="http://www.datapower.com/extensions" xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx" xmlns:date="http://exslt.org/dates-and-times" extension-element-prefixes="dp date">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select="//json:array"/>
</xsl:template>
</xsl:stylesheet>
input XML:
<json:object xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx">
<json:object name="Header">
<json:string name="Action">http://webs.abcd.com/CService</json:string>
<json:string name="RelatesTo">urn:uuid:9455ee68-bc4d-4e6a-9174-fb2000c18e24</json:string>
</json:object>
<json:object name="Body">
<json:object name="GetSimpleCLResponse">
<json:object name="GetSimpleCLResult">
<json:array name="SimpleCarrier">
<json:object>
<json:string name="Code">m9</json:string>
<json:string name="Name">1B9FHQK</json:string>
</json:object>
<json:object>
<json:string name="Code">25</json:string>
<json:string name="Name">1TIME</json:string>
</json:object>
</json:array>
</json:object>
</json:object>
</json:object>
</json:object>
Output XML:
<json:object xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx" xsi:schemaLocation="http://www.datapower.com/schemas/json jsonx.xsd">
<json:array name="airlines">
<json:object>
<json:string name="id">m9</json:string>
<json:string name="name">1B9FHQK</json:string>
</json:object>
<json:object>
<json:number name="id">25</json:number>
<json:string name="name">1TIME</json:string>
</json:object>
</json:array>
</json:object>
AFAICT, all you need to do is add:
<xsl:template match="/">
<xsl:apply-templates select="//json:array"/>
</xsl:template>
to the first stylesheet.
Related
I have multiple occurence nodes which need to be generated at output using XSLT transformation. Could you please help me on this.
Following XSLT code only generate one node occurrence only. Could you please help me with below XSLT code how to generate multiple nodes elements in Input XML
Input XML
<?xml version="1.0" encoding="UTF-8" ?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" >
<soapenv:Body>
<ns1:getGenResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
<ns1:getGenReturn xsi:type="soapenc:Array" soapenc:arrayType="xsd:anyType[2]" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
</ns1:getGenReturn>
</ns1:getGenResponse>
<multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns2:Gen" xmlns:soapenc=http://schemas.xmlsoap.org/soap/encoding/>
<name xsi:type="xsd:string">ULM</name>
<mail xsi:type="xsd:string">ulm#gmail.com</mail>
</multiRef>
<multiRef id="id1" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns3:Gen" " xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<name xsi:type="xsd:string">ABC</name>
<mail xsi:type="xsd:string">abc#gmail.com</mail>
</multiRef>
</soapenv:Body>
</soapenv:Envelope>
XSLT Code used for this transformation
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" x
xmlns:response="http://tempuri.org/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- Output -->
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:if test="//soap:Body/multiRef">
<xsl:element name="getGenResponse">
<xsl:element name="getGenReturn">
<xsl:element name="name"><xsl:value-of select="//name"/></xsl:element>
<xsl:element name="mail"><xsl:value-of select="//mail"/></xsl:element>
</xsl:element>
</xsl:element>
</xsl:if>
</xsl:template>
<!-- 'Copy ' node -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Output from above XSLT
<?xml version="1.0" encoding="UTF-8"?>
<getGenResponse>
<getGenReturn>
<name> ULM </name>
<mail>ulm#gmail.com<mail>
</getGenReturn>
/getGenResponse>
Output expected
<?xml version="1.0" encoding="UTF-8"?>
<getGenResponse>
<getGenReturn>
<name> ULM </name>
<mail>ulm#gmail.com<mail>
</getGenReturn>
<getGenReturn>
<name>ABC</name>
<mail>abc#gmail.com<mail>
</getGenReturn>
/getGenResponse>
At you moment all you are doing is testing a multiRef element exists, and outputting only one new getGenReturn element.
All you really need to do is replace the xsl:if with xsl:for-each to select all the elements, then you will get one getGenReturn for each. And also change the xsl:value-of to use a relative path
<xsl:template match="/">
<xsl:element name="getGenResponse">
<xsl:for-each select="//soap:Body/multiRef">
<xsl:element name="getGenReturn">
<xsl:element name="name"><xsl:value-of select="name"/></xsl:element>
<xsl:element name="mail"><xsl:value-of select="mail"/></xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
Or better still, do this, as xsl:element is not really needed here if you are using static names
<xsl:template match="/">
<getGenResponse>
<xsl:for-each select="//soap:Body/multiRef">
<getGenReturn>
<name><xsl:value-of select="name"/></name>
<mail><xsl:value-of select="mail"/></mail>
</getGenReturn>
</xsl:for-each>
</getGenResponse>
</xsl:template>
Note, you don't actually need the identity template in this case. Try this XSLT:
<xsl:stylesheet version="1.0" xmlns:response="http://tempuri.org/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="soap response">
<!-- Output -->
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<getGenResponse>
<xsl:for-each select="//soap:Body/multiRef">
<getGenReturn>
<name><xsl:value-of select="name"/></name>
<mail><xsl:value-of select="mail"/></mail>
</getGenReturn>
</xsl:for-each>
</getGenResponse>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:response="http://tempuri.org/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="soap response">
<!-- Output -->
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<getGenResponse>
<xsl:for-each select="//soap:Body/multiRef">
<getGenReturn>
<name><xsl:value-of select="name"/></name>
<mail><xsl:value-of select="mail"/></mail>
</getGenReturn>
</xsl:for-each>
</getGenResponse>
</xsl:template>
</xsl:stylesheet>
I have xml file with structure like this:
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">
<changeSet author="system" id="65D7AFA9-17F1-4406-997E-D2B42A0E9008" dbms="oracle">
<sql>GRANT SELECT,INSERT,UPDATE,DELETE ON ${dbSchema}.CATALOG TO ${appUser}</sql>
<rollback>REVOKE SELECT,INSERT,UPDATE,DELETE ON ${dbSchema}.CATALOG FROM ${appUser}</rollback>
</changeSet>
<changeSet author="system" id="E2731435-DCEE-4B7E-BA60-20A87E75227A" dbms="oracle">
<sql>GRANT SELECT,INSERT,UPDATE,DELETE ON ${dbSchema}.CATALOGATTRIBUTE TO ${appUser}</sql>
<rollback>REVOKE SELECT,INSERT,UPDATE,DELETE ON ${dbSchema}.CATALOGATTRIBUTE FROM ${appUser}</rollback>
</changeSet>
<changeSet author="system" id="65D7AFA9-17F1-4406-997E-D2B42A0E9008" dbms="oracle">
<createTable ...>
</changeSet>
</databaseChangeLog>
I'd like to output all changeSets where sql contains one of tables to one document and all others (which doesn't contain the table name) to other document. I was thinking about appending stuff to variable and at the end print two variables, but that doesn't work (or I don't know how to process further).
<xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:uuid="http://uuid.util.java"
exclude-result-prefixes="uuid">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:variable name="tables"
select="('CATALOG','CATALOGATTRIBUTE','EVENTTYPES')"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="changeSet[sql]">
<xsl:variable name="changeSet" select="."/>
<xsl:variable name="sql" select="sql"/>
<xsl:for-each select="$tables">
<!--<xsl:variable name="selected" select="sql[contains(text(),concat('${dbSchema}.', ., ' '))]"/>-->
<xsl:variable name="tableName">
<xsl:value-of select="."/>
<xsl:value-of select="' '"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="contains($sql, $tableName)">
<xsl:copy-of select="$changeSet"/>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:transform>
can I somehow gather all changeSet which match tables and then all changeSets which doe not?
ps: I'm using Saxon-HE-9.8.0-14 for processing.
Thanks
Consider the following simplified example:
XML
<databaseChangeLog>
<changeSet>
<sql>ALPHA,BRAVO,CHARLIE</sql>
</changeSet>
<changeSet>
<sql>BRAVO,CHARLIE,DELTA</sql>
</changeSet>
<changeSet>
<sql>DELTA,ECHO,FOXTROT</sql>
</changeSet>
<changeSet>
<sql>FOXTROT,GOLF,HOTEL</sql>
</changeSet>
</databaseChangeLog>
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="tables" select="('BRAVO', 'GOLF')"/>
<xsl:template match="/databaseChangeLog">
<xsl:variable name="group1" select="changeSet[some $t in $tables satisfies contains(sql, $t)]" />
<xsl:copy>
<group1>
<xsl:copy-of select="$group1"/>
</group1>
<group2>
<xsl:copy-of select="changeSet except $group1"/>
</group2>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog>
<group1>
<changeSet>
<sql>ALPHA,BRAVO,CHARLIE</sql>
</changeSet>
<changeSet>
<sql>BRAVO,CHARLIE,DELTA</sql>
</changeSet>
<changeSet>
<sql>FOXTROT,GOLF,HOTEL</sql>
</changeSet>
</group1>
<group2>
<changeSet>
<sql>DELTA,ECHO,FOXTROT</sql>
</changeSet>
</group2>
</databaseChangeLog>
Demo: https://xsltfiddle.liberty-development.net/jyRYYiP
A better solution would be to use tokenize():
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="tables" select="('BRAVO', 'GOLF')"/>
<xsl:template match="/databaseChangeLog">
<xsl:variable name="group1" select="changeSet[tokenize(sql, ',') = $tables]" />
<xsl:copy>
<group1>
<xsl:copy-of select="$group1"/>
</group1>
<group2>
<xsl:copy-of select="changeSet except $group1"/>
</group2>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Demo: https://xsltfiddle.liberty-development.net/jyRYYiP/1
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
convert xml to jsonx using xslt
Can anyone help me out in getting the below with an array..I have to generate the generalised xsl..
Input XML:
<accounts>
<displayOrdinal>0</displayOrdinal>
<name>String</name>
<account>
<accountNumber>String</accountNumber>
<name>String</name>
<balance>
<balanceAmount>0.0</balanceAmount>
</balance>
<balance>
<balanceAmount>0.0</balanceAmount>
</balance>
<properties>
<displayOrdinal>0</displayOrdinal>
</properties>
<properties>
<displayOrdinal>0</displayOrdinal>
</properties>
<usage>
<type>String</type>
</usage>
<usage>
<type>String</type>
</usage>
</account>
<account>
<accountNumber>String</accountNumber>
<name>String</name>
<balance>
<balanceAmount>0.0</balanceAmount>
</balance>
<balance>
<balanceAmount>0.0</balanceAmount>
</balance>
<properties>
<displayOrdinal>0</displayOrdinal>
</properties>
<properties>
<displayOrdinal>0</displayOrdinal>
</properties>
<usage>
<type>String</type>
</usage>
<usage>
<type>String</type>
</usage>
</account>
</accounts>
Output:
<json:object xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx">
<json:object name="accounts">
<json:string name="displayOrdinal">0</json:string>
<json:string name="name">String</json:string>
<json:array name="account">
<json:object>
<json:string name="accountNumber">String</json:string>
<json:string name="name">String</json:string>
<json:array name="balance">
<json:object>
<json:string name="balanceAmount">0.0</json:string>
</json:object>
<json:object>
<json:string name="balanceAmount">0.0</json:string>
</json:object>
</json:array>
<json:array name="properties">
<json:object>
<json:string name="displayOrdinal">0</json:string>
</json:object>
<json:object>
<json:string name="displayOrdinal">0</json:string>
</json:object>
</json:array>
<json:array name="usage">
<json:object>
<json:string name="type">String</json:string>
</json:object>
<json:object name="usage">
<json:string name="type">String</json:string>
</json:object>
</json:array>
</json:object>
<json:object>
<json:string name="accountNumber">String</json:string>
<json:string name="name">String</json:string>
<json:object name="balance">
<json:string name="balanceAmount">0.0</json:string>
</json:object>
<json:array name="balance">
<json:object>
<json:string name="balanceAmount">0.0</json:string>
</json:object>
<json:object>
<json:string name="displayOrdinal">0</json:string>
</json:object>
<json:object>
<json:string name="displayOrdinal">0</json:string>
</json:object>
</json:array>
<json:array name="usage">
<json:object>
<json:string name="type">String</json:string>
</json:object>
<json:object>
<json:string name="type">String</json:string>
</json:object>
</json:array>
</json:object>
</json:array>
</json:object>
</json:object>
I am using the below xslt and output but not as expected above.Could any one please help me.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx">
<xsl:output method="xml" indent="yes" encoding="UTF-8" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<!-- Array -->
<xsl:template match="*[*[2]][name(*[1])=name(*[2])]">
<json:object name="{name()}">
<json:array name="{name(*[1])}">
<xsl:apply-templates/>
</json:array>
</json:object>
</xsl:template>
<!-- Array member -->
<xsl:template match="*[parent::*[ name(*[1])=name(*[2]) ]] | /">
<json:object>
<xsl:apply-templates/>
</json:object>
</xsl:template>
<!-- Object -->
<xsl:template match="*">
<json:object name="{name()}">
<xsl:apply-templates/>
</json:object>
</xsl:template>
<!-- String -->
<xsl:template match="*[not(*)]">
<json:string name="{name()}">
<xsl:value-of select="."/>
</json:string>
</xsl:template>
</xsl:stylesheet>
May be you meant to say that Groups should be an array and Group should be an object instead of the other way around?
Try this...
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx"
exclude-result-prefixes="xsl xs">
<xsl:output indent="yes" encoding="UTF-8" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/">
<json:object>
<xsl:apply-templates />
</json:object>
</xsl:template>
<!-- Array -->
<xsl:template match="*[*[2]][name(*[1])=name(*[2])]">
<json:array name="{name()}">
<xsl:apply-templates />
</json:array>
</xsl:template>
<!-- Object -->
<xsl:template match="*">
<json:object name="{name()}">
<xsl:apply-templates />
</json:object>
</xsl:template>
<!-- String -->
<xsl:template match="*[not(*)]">
<json:string name="{name()}">
<xsl:value-of select="." />
</json:string>
</xsl:template>
</xsl:stylesheet>
...the output is this...
<json:object xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx">
<json:object name="Login">
<json:array name="Groups">
<json:object name="Group">
<json:string name="Name">john</json:string>
<json:string name="Password"/>
</json:object>
<json:object name="Group">
<json:string name="Name">john</json:string>
<json:string name="Password"/>
</json:object>
</json:array>
</json:object>
</json:object>
Update
In response to the OP's updated requirements, here is a new solution.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx">
<xsl:output indent="yes" encoding="UTF-8" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<!-- Array -->
<xsl:template match="*[*[2]][name(*[1])=name(*[2])]">
<json:object name="{name()}">
<json:array name="{name(*[1])}">
<xsl:apply-templates />
</json:array>
</json:object>
</xsl:template>
<!-- Array member -->
<xsl:template match="*[parent::*[ name(*[1])=name(*[2]) ]] | /">
<json:object>
<xsl:apply-templates />
</json:object>
</xsl:template>
<!-- Object -->
<xsl:template match="*">
<json:object name="{name()}">
<xsl:apply-templates />
</json:object>
</xsl:template>
<!-- String -->
<xsl:template match="*[not(*)]">
<json:string name="{name()}">
<xsl:value-of select="." />
</json:string>
</xsl:template>
</xsl:stylesheet>
Output is so...
<json:object xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx">
<json:object name="Login">
<json:object name="Groups">
<json:array name="Group">
<json:object>
<json:string name="Name">john</json:string>
<json:string name="Password"></json:string>
</json:object>
<json:object>
<json:string name="Name">john</json:string>
<json:string name="Password"></json:string>
</json:object>
</json:array>
</json:object>
</json:object>
</json:object>
My input xml would be like this with json namespaces..
<json:object xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<json:object name="Login">
<json:object name="Group">
<json:object name="TargetSystem">
<json:string name="Name">john</json:string>
<json:string name="Password"/>
</json:object>
</json:object>
</json:object>
</json:object>
I need the output like this
<Login>
<Group>
<TargetSystem>
<Name>john</Name>
<Password/>
</TargetSystem>
</Group>
</Login>
I have to create this xml using the attribute name value in the input xml using xslt.
I am using the below xslt.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx">
<xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
<xsl:template match="/">
<xsl:apply-templates select="json:object/*"/>
</xsl:template>
<xsl:template match="json:object">
<xsl:element name="{#name}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Using this I am getting only john.
I have to use some looping concept..
Could anyone please help me how can I achieve this?
If minimal XSLT is your thing, it is possible to come up with a generic XSLT that would work with any namespace.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
<xsl:template match="*[#name]">
<xsl:element name="{#name}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
In other words, this will match any element with a #name attribute, and create an element of that name instead. Because the root element has no such attribute, it won't be output, but the default template match will just continue to process its children.
I think you want
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0"
xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx"
exclude-result-prefixes="json">
<xsl:template match="/json:object">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="json:object[#name]">
<xsl:element name="{#name}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="json:string[#name]">
<xsl:element name="{#name}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Can anyone help me out in getting the below with an array..I have to generate the generalised xsl..
Input XML:
<Login>
<Groups>
<Group>
<Name>john</Name>
<Password/>
</Group>
<Group>
<Name>john</Name>
<Password/>
</Group>
</Groups>
</Login>
Output:
<json:object xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<json:object name="Login">
<json:object name="Groups">
<json:array name="Group">
<json:object>
<json:string name="Name">john</json:string>
<json:string name="Password"/>
</json:object>
<json:object>
<json:string name="Name">john</json:string>
<json:string name="Password"/>
</json:object>
</json:array>
</json:object>
</json:object>
</json:object>
More generalized solution. Requires XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<xsl:element name="json:object">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
<xsl:template match="*[*]">
<xsl:param name="nodeName" select="name()" />
<xsl:variable name="firstNodeName" select="name(*[1])" />
<xsl:element name="json:object">
<xsl:if test="$nodeName">
<xsl:attribute name="name" select="$nodeName" />
</xsl:if>
<xsl:choose>
<xsl:when test="(count(*) > 1) and (every $x in */name() satisfies $x=$firstNodeName)">
<xsl:element name="json:array">
<xsl:attribute name="name" select="$firstNodeName" />
<xsl:apply-templates >
<xsl:with-param name="nodeName" select="''" />
</xsl:apply-templates>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates />
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:template>
<xsl:template match="*[not(*)]">
<xsl:element name="json:string">
<xsl:attribute name="name">
<xsl:value-of select="name()" />
</xsl:attribute>
<xsl:value-of select="text()" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Applied to the provided sample XML, produces following output:
<?xml version="1.0" encoding="UTF-8"?>
<json:object xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx">
<json:object name="Login">
<json:object name="Groups">
<json:array name="Group">
<json:object>
<json:string name="Name">john</json:string>
<json:string name="Password"></json:string>
</json:object>
<json:object>
<json:string name="Name">john</json:string>
<json:string name="Password"></json:string>
</json:object>
</json:array>
</json:object>
</json:object>
</json:object>
The above solution was tested on this site: http://xslttest.appspot.com/
EDIT:
every $x in */name() satisfies $x=$firstNodeName is XPATH 2.0 construction that checks if all the elements in */name() sequence are equal to $firstNodeName. So this whole condition actually means checking if a node has more than one child with the same name - this is a condition for checking if we're dealing with json:array case.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx">
<xsl:output indent="yes" encoding="UTF-8" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<!-- Array -->
<xsl:template match="*[*[2]][name(*[1])=name(*[2])]">
<json:object name="{name()}">
<json:array name="{name(*[1])}">
<xsl:apply-templates />
</json:array>
</json:object>
</xsl:template>
<!-- Array member -->
<xsl:template match="*[parent::*[ name(*[1])=name(*[2]) ]] | /">
<json:object>
<xsl:apply-templates />
</json:object>
</xsl:template>
<!-- Object -->
<xsl:template match="*">
<json:object name="{name()}">
<xsl:apply-templates />
</json:object>
</xsl:template>
<!-- String -->
<xsl:template match="*[not(*)]">
<json:string name="{name()}">
<xsl:value-of select="." />
</json:string>
</xsl:template>
</xsl:stylesheet>
you can try the below generic xslt :
<?xml version="1.0"?>
<xsl:stylesheet xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output omit-xml-declaration="yes" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- Array -->
<xsl:template match="*[*[2]][name(*[1])=name(*[2])]">
<json:object name="{name()}">
<json:array name="{name(*[1])}">
<xsl:apply-templates/>
</json:array>
</json:object>
</xsl:template>
<!-- Array member -->
<xsl:template match="*[parent::*[ name(*[1])=name(*[2]) ]] | /">
<json:object>
<xsl:apply-templates/>
</json:object>
</xsl:template>
<!-- Object -->
<xsl:template match="*">
<json:object name="{name()}">
<xsl:apply-templates/>
</json:object>
</xsl:template>
<!-- String -->
<xsl:template match="*[not(*)]">
<json:string name="{name()}">
<xsl:value-of select="."/>
</json:string>
</xsl:template>
</xsl:stylesheet>