Sending value with different tag XSLT - xslt

is there any chance can sending value to output other node response, with different path from there input request. i have input and response tag like this
Input Request:
<Root>
<Items>
<Item1>Rambutan12</Item1>
</Items>
</Root>
and i try with this code for add new node with additional info at Response
i try like this
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="text"/>
<xsl:template match="/">
<Root>
<ItemsResponse>
<xsl:call-templates select="items">
<xsl:with-param name="item1s" select="//Root/Items/Item1"/>
</xsl:call-templates>
</ItemsResponse>
</Root>
</xst:template>
<xsl:template name="items">
<xsl:param name="item1s"/>
<xsl:variable name="information">
<xsl:choose>
<xsl:when test="fn:matches($item1s, '^[a-zA-Z]*$') ">
<Item1><xsl:value-of select="$item1s"/></Item1>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<Item1><xsl:value-of select="$item1s"/></Item1>
<xsl:apply-templates select="Item1Information"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="Item1Information">
<xsl:copy>
<Item1Information>Wrong Failed Format Input</Item1Information>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Expected Result was like this
<Root>
<ItemsResponse>
<Item1>Rambutan12</Item1>
<Item1Information>Input Failed Format</ItemInformation>
</ItemsResponse>
</Root>
Any tips like for this case, thanks

It is very difficult to understand what your question is.
On the off-chance that I am guessing correctly, and that you want to add an error warning when Item1 contains any characters other than the 26 letters of the English alphabet, then you could do simply:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/Root">
<Root>
<ItemsResponse>
<xsl:copy-of select="Items/Item1"/>
<xsl:if test="translate(Items/Item1, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', '')">
<Item1Information>Input Failed Format</Item1Information>
</xsl:if>
</ItemsResponse>
</Root>
</xsl:template>
</xsl:stylesheet>

Related

XMLT : replace values with values found in another xml

I have a file called ori.xml:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<container>
<elA>
<el1>value1</el1>
<el2>value2</el2>
</elA>
<elB>
<el3>value3</el3>
<el4>value4</el4>
<el5>value5</el5>
</elB>
<elC>
<el6>value5</el6>
</elC>
</container>
</root>
and another one called modifs.xml:
<?xml version="1.0" encoding="UTF-8"?>
<els>
<el2>newvalue2</el2>
<el5>newvalue5</el5>
</els>
and I would like to obtain result.xml:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<container>
<elA>
<el1>value1</el1>
<el2>newvalue2</el2>
</elA>
<elB>
<el3>value3</el3>
<el4>value4</el4>
<el5>newvalue5</el5>
</elB>
<elC>
<el6>value5</el6>
</elC>
</container>
</root>
I'm a beginner in XSLT.
So I started to write a stylesheet with which I'm able to change value2 into newvalue2:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:param name="fileName" select="'modifs.xml'" />
<xsl:param name="modifs" select="document($fileName)" />
<xsl:param name="updateEl" >
<xsl:value-of select="$modifs/els/el2" />
</xsl:param>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//elA/el2">
<xsl:copy>
<xsl:apply-templates select="$updateEl" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
But now I have to modify this stylesheet to be able to know which elements are in modifs.xml and find them in ori.xml. I don't know how to do that. Could you help please ?
I would use a key:
<xsl:key name="ref-change" match="els/*" use="local-name()"/>
<xsl:template match="*[key('ref-change', local-name(), $modifs)]">
<xsl:copy-of select="key('ref-change', local-name(), $modifs)"/>
</xsl:template>
However, using the third argument for the key function is only supported in XSLT 2 and later thus if you use an XSLT 1 processor you need to move the logic into the template, that requires using for-each to "switch" the context document
<xsl:template match="*">
<xsl:variable name="this" select="."/>
<xsl:for-each select="$modifs">
<xsl:choose>
<xsl:when test="key('ref-change', local-name($this))">
<xsl:copy-of select="key('ref-change', local-name($this))"/>
</xsl:when>
<xsl:otherwise>
<xsl:for-each select="$this">
<xsl:call-template name="identity"/>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
Put name="identity" on your identity transformation template.

xslt extract and sort leaf nodes by name - unexpected result

I wanted to extract leaf nodes and have them sorted.
My XSL gives unexpected results. How can I solve this?
Input
<root>
<b>
<b33 zzz="2" fff="3"></b33>
<b11></b11>
<b22></b22>
</b>
<a>
<a27></a27>
<a65 fff="0" eee="2" zzz="10"></a65>
<a11></a11>
</a>
</root>
Xsl
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<root>
<xsl:call-template name="leafnodes"/>
</root>
</xsl:template>
<xsl:template match="*[not(*)]|#*" name="leafnodes">
<xsl:copy>
<xsl:apply-templates select="node()">
<xsl:sort select="name()"/>
</xsl:apply-templates>
<xsl:apply-templates select="#*">
<xsl:sort select="name()"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Output (I would expected it to be sorted, it is not)
<root>
<b33 fff="3" zzz="2" />
<b11 />
<b22 />
<a27 />
<a65 eee="2" fff="0" zzz="10" />
<a11 />
</root>
I would expect the nodes in the order a11, a27, a65, b11, b22, b33.
If I leave out the '[not(*)]', the xsl takes all nodes and sorts them properly.
How can this be solved?
To output all element which have no child sorted by name and the attributes also sorted by name. Try this;
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<root>
<xsl:apply-templates select="//*[not(*)]">
<xsl:sort select="name()"/>
</xsl:apply-templates>
</root>
</xsl:template>
<xsl:template match="*|#*">
<xsl:copy>
<xsl:apply-templates select="#*" >
<xsl:sort select="name()"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Which will generate following output:
<root>
<a11/>
<a27/>
<a65 eee="2" fff="0" zzz="10"/>
<b11/>
<b22/>
<b33 fff="3" zzz="2"/>
</root>

How to remove the rootnodes using XSLT?

Input file:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:root xmlns:ns0="http://xyz.com/separate">
<ns0:root1>
<ns3:Detail xmlns:ns3="http://POProject/Details">
<DetailLines>
<ItemID>
<ItemDescription/>
</DetailLines>
</ns3:Detail>
</ns0:root1>
</ns0:root>
Output file:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:Detail xmlns:ns0="http://POProject/Details">
<DetailLines>
<ItemID>
<ItemDescription/>
</DetailLines>
</ns0:Detail>
Question: I have to remove the root1 and root nodes and need to do small
changes in Detail node. How to write a xslt code to achieve this?
This...
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://xyz.com/separate"
xmlns:ns3="http://POProject/Details">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="*/*/ns3:Detail" />
</xsl:template>
<xsl:template match="ns3:Detail">
<xsl:apply-templates select="." mode="copy-sans-namespace" />
</xsl:template>
<xsl:template match="*" mode="copy-sans-namespace">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:copy-of select="#*"/>
<xsl:apply-templates mode="copy-sans-namespace" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
...will yield this...
<?xml version="1.0" encoding="utf-8"?>
<ns3:Detail xmlns:ns3="http://POProject/Details">
<DetailLines>
<ItemID />
<ItemDescription />
</DetailLines>
</ns3:Detail>
I'm not sure it is possible to control the prefix. The XDM data model does not consider it to be significant information.
UDPATE
To get the prefix rename, I thought you would have to go to an XML 1.1 supporting XSLT processor (allowing prefix undefine), but I found a way to do it with XML 1.0 . Try this ...
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://xyz.com/separate">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/" xmlns:ns3="http://POProject/Details">
<xsl:apply-templates select="*/*/ns3:Detail" />
</xsl:template>
<xsl:template match="ns0:Detail" xmlns:ns0="http://POProject/Details">
<ns0:Detail xmlns:ns0="http://POProject/Details">
<xsl:apply-templates select="*" mode="copy-sans-namespace" />
</ns0:Detail>
</xsl:template>
<xsl:template match="*" mode="copy-sans-namespace">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:copy-of select="#*"/>
<xsl:apply-templates mode="copy-sans-namespace" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>

XSLT - transform XML in REST response result

I am currently trying to use XSLT to convert some XML pseudo-code to a rest response result
For example, with the following xml:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:functions="http://foo.com/api/rest">
<item bar="foo">some item</item>
<functions:fetch a="3" b="foo" />
</root>
And if the result of http://foo.com/services/rest/fetch/a/3/b/foo is:
<?xml version="1.0" encoding="UTF-8"?>
<rsp stat="ok">
<book>
<title>Ethics</title>
</book>
<book>
<title>Beyond Good and Evil</title>
</book>
</rsp>
The result of the XSLT parsing I am trying to obtain is:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:functions="http://foo.com/api/rest">
<item bar="foo">some item</item>
<book>
<title>Ethics</title>
</book>
<book>
<title>Beyond Good and Evil</title>
</book>
</root>
I know I can use <xsl:value-of select="document('http://foo.com/services/rest/fetch/a/3/b/foo')"/> to make the request, but I am stuck on how to generate and process it in the same XSLT.
Any help will be greatly appreciated, Thanks in advance!
Here is one possible pure XSLT 1.0 solution:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:functions="http://foo.com/api/rest"
exclude-result-prefixes="functions">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vDynPart">
<xsl:for-each select="/*/functions:*/#*">
<xsl:value-of select="concat('/', name(), '/', .)"/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="vRes" select=
"document(concat('http://foo.com/services/rest/fetch',
$vDynPart)
)"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
<xsl:apply-templates select="$vRes/*/node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="functions:*"/>
</xsl:stylesheet>
Thanks to the answer from Dimitre, I found a solution!
(I make a new reply as I tuned Dimitre solution a little to work with any function name and multiple functions in the same XML)
Here the xslt:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:functions="http://foo.com/api/rest"
exclude-result-prefixes="functions">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="functions:*">
<xsl:variable name="request_function">
<xsl:value-of select="local-name(.)"/>
</xsl:variable>
<xsl:variable name="request_parameters">
<xsl:for-each select="#*">
<xsl:value-of select="concat('/', name(), '/', .)"/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="rest_response" select="document(concat('http://foo.com/services/rest/', $request_function, $request_parameters) )"/>
<xsl:apply-templates select="$rest_response/*/node()"/>
</xsl:template>
</xsl:stylesheet>
Thanks!

xslt to add default value where element doesn't exist

I'm struggling with trying to test to see if an element exists. If it doesn't, I'd like to add in a default value. Here's my XML
<records>
<record>
<InstanceData>
<instance>
<FirstName>Johhny</FirstName>
<LastName>Jenkins</LastName>
<AlbumCount>3</AlbumCount>
</instance>
</InstanceData>
</record>
<record>
<InstanceData>
<instance>
<FirstName>Art</FirstName>
<LastName>Tatum</LastName>
<AlbumCount>7</AlbumCount>
</instance>
</InstanceData>
</record>
<record>
<InstanceData>
<instance>
<FirstName>Count</FirstName>
<LastName>Basie</LastName>
</instance>
</InstanceData>
</record>
</records>
I'd like to be able to copy over existing values and set any record without the Album Count element to <AlbumCount>0</AlbumCount>. This is the xslt I've been working with but I think I'm some way off the mark.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="Records">
<xsl:for-each select="node()">
<xsl:choose>
<xsl:when test="name()='AlbumCount'">
<xsl:element name="AlbumCount">
<xsl:choose>
<xsl:when test="name()='AlbumCount'">
<xsl:copy-of select=".">
</xsl:copy-of>
</xsl:when>
<xsl:otherwise>
<AlbumCount>0</AlbumCount>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select=".">
</xsl:copy-of>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Thanks for looking.
Try this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="no"/>
<!-- identity template -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="instance[not(AlbumCount)]">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
<AlbumCount>0</AlbumCount>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Start with the identity transformation, then just handle the exception differently.
You test for the existance of an element simply with the elements name, for example:
<xsl:if test="not(AlbumCount)">
<AlbumCount>0</AlbumCount>
</xsl:if>
The simpler way to do what you want is to use the standard copy template combined with a special rule for places where AlbumCount elements need adding:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<!-- Standard copy template -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<!-- Special template to add AlbumCount elements where required -->
<xsl:template match="records/record/InstanceData/instance">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
<xsl:if test="not(AlbumCount)">
<AlbumCount>0</AlbumCount>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>