XSL transformation returns blank value - xslt

I have a problem to retrieve my input data when I do an xsl transformation.
This is my original xml input (input xml)
<?xml version="1.0" encoding="UTF-8"?> <ns2:pointOfSale
xmlns:ns2="http://example.net/.."
mode="CREATE" timestamp="2018-10-12T09:34:53.14+02:00"><ns2:id
type="AMP">15573</ns2:id></ns2:pointOfSale>
This is my output result (output xml)
<?xml version="1.0" encoding="utf-8"?><clients xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="setClients.xsd" encryptedData="N"><client clientID=""></client></clients>
this is my xsl
<?xml version="1.1" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns2="http://example.net/.."
exclude-result-prefixes="xs xd"
version="2.0">
<xsl:output method="xml" version="1.0" encoding="utf-8" omit-xml-declaration="no" indent="no" />
<xsl:strip-space elements="*" />
<xsl:template match="/">
<xsl:element name="clients">
<xsl:attribute
name="xsi:noNamespaceSchemaLocation">setClients.xsd</xsl:attribute>
<xsl:attribute name="encryptedData">N</xsl:attribute>
<xsl:element name="client">
<xsl:attribute name="clientID" >
<xsl:value-of select="ns2:id"/>
</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Like you see, the value of element ID is empty ("")
What's the problem? is it the match() ? Maybe a problem of namespace?
thank you.

There are two reasons why <xsl:value-of select="id"/> is not returning anything.
Firstly, your template matches "/" which is the document node. This is the parent of the ns2:pointOfSale node in your XML. The document node does not have id as a child, so <xsl:value-of select="id"/> will not find anything. To fix this, you should match the root element (ns2:pointOfSale in this case) instead
<xsl:template match="/*">
The second issue is with namespaces. Assuming there was a namespace declaration in your XML of the form xmlns:ns2="xxx.xxxx" you would add the same declaration in your XSLT (on the xsl:stylesheet element) and then you could this.
<xsl:value-of select="ns2:id"/>
Without any reference to the namespace in your XSLT, it would be looking for an id element in no namespace.
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exclude-result-prefixes="xs xd"
xmlns:ns2="xxx.xxxx"
version="2.0">
<xsl:output method="xml" version="1.0" encoding="utf-8" omit-xml-declaration="no" indent="no" />
<xsl:strip-space elements="*" />
<xsl:template match="/*">
<xsl:element name="clients">
<xsl:attribute
name="xsi:noNamespaceSchemaLocation">setClients.xsd</xsl:attribute>
<xsl:attribute name="encryptedData">N</xsl:attribute>
<xsl:element name="client">
<xsl:attribute name="clientID" >
<xsl:value-of select="ns2:id"/>
</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Actually, as you are using XSLT 2.0, you could use xpath-default-namespace instead, which would mean XSLT would treat any unprefixed element in a select expression as part of that namespace.
Try this too....
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exclude-result-prefixes="xs xd"
xpath-default-namespace="xxx.xxxx"
version="2.0">
<xsl:output method="xml" version="1.0" encoding="utf-8" omit-xml-declaration="no" indent="no" />
<xsl:strip-space elements="*" />
<xsl:template match="/*">
<xsl:element name="clients">
<xsl:attribute
name="xsi:noNamespaceSchemaLocation">setClients.xsd</xsl:attribute>
<xsl:attribute name="encryptedData">N</xsl:attribute>
<xsl:element name="client">
<xsl:attribute name="clientID" >
<xsl:value-of select="id"/>
</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Better still, use Attribute Value Templates (and avoid the use of xsl:element) to simplify the XSLT to this...
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exclude-result-prefixes="xs xd"
xpath-default-namespace="xxx.xxxx"
version="2.0">
<xsl:output method="xml" version="1.0" encoding="utf-8" omit-xml-declaration="no" indent="no" />
<xsl:strip-space elements="*" />
<xsl:template match="/*">
<clients xsi:noNamespaceSchemaLocation="setClients.xsd" encryptedData="N">
<client clientID="{id}" />
</clients>
</xsl:template>
</xsl:stylesheet>

Related

Fetch internal tags in the xml using XSLT

when I execute the below stylesheet
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|#*" >
<xsl:copy>
<xsl:variable name="manu" select="node()|#*"/>
<xsl:apply-templates select="$manu"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I'm getting the below output:-
<?xml version="1.0" encoding="UTF-8" ?>
<A1>
<B1>
<FILES>
<StudentData>
<Student>0001</Student>
<Student>0002</Student>
</StudentData>
</FILES>
</B1>
</A1>
Now I want to select only the StudentData:-
Expected Output:-
<StudentData>
<Student>0001</Student>
<Student>0002</Student>
</StudentData>
How to match this in XSLT?
There a lots of ways. i.e. you could match on root and then just do a copy of the element using the xpath to that element like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select="A1/B1/FILES/StudentData"/>
</xsl:template>
</xsl:stylesheet>
Why using an identity template? As far as I understand your problem, the simple solution is this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="StudentData" >
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
If you want to filter the empty lines out of your output, add a template matching the text nodes for that purpose:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="StudentData" >
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="text()"/>
<!-- this tricky template prevents empty white lines in output -->
</xsl:stylesheet>

XSL won't write xmlns:xsl?

How do I write the XSL namespace in my output?
I'm using XSL to analyze an XSL document and report problems it finds, including copying the node. The problem is that I can't get xmlns:xsl="http://www.w3.org/1999/XSL/Transform" written into the output's root node, which means it gets repeated every time I copy an xsl:* element.
This doesn't seem to happen with other namespaces. For example, take the following XSL
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="custom uri" xmlns:custom2="custom2 uri" exclude-result-prefixes="" version="3.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/" name="xsl:initial-template">
<custom:element xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:element name="custom2:function">
<xsl:attribute name="name">whatever</xsl:attribute>
</xsl:element>
<xsl:element name="custom2:function">
<xsl:attribute name="name">whatever2</xsl:attribute>
</xsl:element>
</custom:element>
</xsl:template>
</xsl:stylesheet>
When run against any XML document, I get what I expect except that xmlns:xsl is missing from custom:element even though I specify it and exclude-result-prefixes is explicitly blank... but that's fine, it's not used in the output.
<custom:element xmlns:custom="custom uri" xmlns:custom2="custom2 uri">
<custom2:function name="whatever"/>
<custom2:function name="whatever2"/>
</custom:element>
However, if I replace both name="custom2:function" with name="xsl:function" like so...
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="custom uri" xmlns:custom2="custom2 uri" exclude-result-prefixes="" version="3.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/" name="xsl:initial-template">
<custom:element xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:element name="xsl:function">
<xsl:attribute name="name">whatever</xsl:attribute>
</xsl:element>
<xsl:element name="xsl:function">
<xsl:attribute name="name">whatever2</xsl:attribute>
</xsl:element>
</custom:element>
</xsl:template>
</xsl:stylesheet>
then xmlns:xsl is still missing from custom:element and I get
<custom:element xmlns:custom="custom uri" xmlns:custom2="custom2 uri">
<xsl:function xmlns:xsl="http://www.w3.org/1999/XSL/Transform" name="whatever"/>
<xsl:function xmlns:xsl="http://www.w3.org/1999/XSL/Transform" name="whatever2"/>
</custom:element>
instead of what I want:
<custom:element xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="custom uri" xmlns:custom2="custom2 uri">
<xsl:function name="whatever"/>
<xsl:function name="whatever2"/>
</custom:element>
How do I change my stylesheet to declare xmlns:xsl="http://www.w3.org/1999/XSL/Transform" I the root node?
With Saxon a namespace alias helps:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="custom-uri" xmlns:custom2="custom2-uri" version="3.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl" xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias"/>
<xsl:template match="/" name="xsl:initial-template">
<custom:element xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias">
<xsl:element name="xsl:function">
<xsl:attribute name="name">whatever</xsl:attribute>
</xsl:element>
<xsl:element name="xsl:function">
<xsl:attribute name="name">whatever2</xsl:attribute>
</xsl:element>
</custom:element>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/gVhEaiX outputs
<custom:element xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:custom="custom-uri"
xmlns:custom2="custom2-uri">
<xsl:function name="whatever"/>
<xsl:function name="whatever2"/>
</custom:element>
Most times you would just put the namespace declaration on the root element with e.g.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="custom-uri" xmlns:custom2="custom2-uri" version="3.0"
xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl" />
<xsl:template match="/" name="xsl:initial-template">
<custom:element>
<xsl:element name="xsl:function">
<xsl:attribute name="name">whatever</xsl:attribute>
</xsl:element>
<xsl:element name="xsl:function">
<xsl:attribute name="name">whatever2</xsl:attribute>
</xsl:element>
</custom:element>
</xsl:template>
</xsl:stylesheet>
I was not sure whether you want to restrict it to a certain element so the first sample declares it on that element and then of course additionally on the xsl:namespace-alias so that it makes sense.

remove text from a node in input XML

i am trying to copy entire input xml in a string for further processing and also i have a requirement to remove text from a particular node (plancode) before copying in the variable. May I know how can i achieve this using xslt
INPUT XML:
<CallMember>
<PlanD>
<abcpr>you</abcpr>
<Desd>Protection</Desd>
<plancode>76789</plancode>
<plaDesc>goody</plaDesc>
</PlanD>
<fType>ONLINE</fType>
</CallMember>
XSLT i am trying :
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xslt" xmlns:func="http://exslt.org/functions" xmlns:dp="http://www.datapower.com/extensions" xmlns:regexp="http://exslt.org/regular-expressions" xmlns:tglfn="http://test.com/tgl" xmlns:date="http://exslt.org/dates-and-times" exclude-result-prefixes="#all" extension-element-prefixes="dp regexp">
<xsl:output method="xml" encoding="UTF-8" indent="yes" omit-xml-declaration="no"/>
<xsl:template match="/">
<xsl:variable name="InputRequest">
<xsl:copy-of select="."/>
</xsl:variable>
<xsl:variable name="modifiedRequest">
<xsl:copy-of select="."/>
<plancode></plancode>
</xsl:variable>
</xsl:template>
OUTput i am expecting in the modifiedRequest variable:
<CallMember>
<PlanD>
<abcpr>you</abcpr>
<Desd>Protection</Desd>
<plancode></plancode> <!-- this value needs to get emptied -->
<plaDesc>goody</plaDesc>
</PlanD>
<fType>ONLINE</fType>
</CallMember>
Use an identity template in combination with an (nearly) empty template for filtering and apply-templates to it:
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xalan="http://xml.apache.org/xslt"
xmlns:func="http://exslt.org/functions"
xmlns:dp="http://www.datapower.com/extensions"
xmlns:regexp="http://exslt.org/regular-expressions"
xmlns:tglfn="http://test.com/tgl"
xmlns:date="http://exslt.org/dates-and-times"
exclude-result-prefixes="#all" extension-element-prefixes="dp regexp">
<xsl:output method="xml" 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="/">
<xsl:variable name="InputRequest">
<xsl:copy-of select="."/>
</xsl:variable>
<!-- copies subtree except matching empty template -->
<xsl:variable name="modifiedRequest">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:variable>
</xsl:template>
<!-- (nearly) empty template copies only element without content -->
<xsl:template match="plancode">
<xsl:copy />
</xsl:template>
</xsl:stylesheet>

How to move out the dynamic result-document into the separate included or imported xsl file

I have a bunch of xsl files. I want to control an indent of result document centrally. I use now the code below in every xsl file. I have an xsl:template name="data" template in each file, but the content of this template is different. Is it possible to move out the content of xsl:template match="/" into the separate xsl file properly and import it in every xsl file. I tried but to no effect. Can someone advise me a working code?
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml">
<xsl:output name="indent" method="html" indent="yes" omit-xml-declaration="yes"/>
<xsl:output name="no_indent" method="html" indent="no" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:variable name="indent" select="//page/view-data/html-indent"/>
<xsl:if test="$indent='yes'">
<xsl:result-document format="indent" >
<xsl:call-template name="data"/>
</xsl:result-document>
</xsl:if>
<xsl:if test="$indent='no'">
<xsl:result-document format="no_indent" >
<xsl:call-template name="data"/>
</xsl:result-document>
</xsl:if>
</xsl:template>
<xsl:template name="data">
<!-- The content is different from file to file -->
</xsl:template>
</xsl:stylesheet>
You seem to have overlooked the fact that there is a much simpler way of doing this.
<xsl:param name="indent" select="'no'"/>
<xsl:output method="html"/>
<xsl:template match="/">
<xsl:result-document indent="{$indent}">
....
</xsl:result-document>
</xsl:template>
and then supply the value of indent as a stylesheet parameter. And in fact there's an even simpler way: you can override the serialisation properties given in the stylesheet with properties supplied from the command line or the Java API: from the command line, just specify !indent=yes or !indent=no.
Yes it is:
Move the repeating code into a new .xsl e.g. main.xsl :
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output name="indent" method="html" indent="yes" omit-xml-declaration="yes"/>
<xsl:output name="no_indent" method="html" indent="no" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:variable name="indent" select="//page/view-data/html-indent"/>
<xsl:if test="$indent='yes'">
<xsl:result-document format="indent" >
<xsl:call-template name="data"/>
</xsl:result-document>
</xsl:if>
<xsl:if test="$indent='no'">
<xsl:result-document format="no_indent" >
<xsl:call-template name="data"/>
</xsl:result-document>
</xsl:if>
</xsl:template>
<xsl:template name="data"/>
</xsl:stylesheet>
Then in your other .xsl files simply use xsl:import at the top of your document :
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="file:///C:/Users/Stefanos/area51/main.xsl"/>
<!--Other stuff here-->
<xsl:template match="extra"/>
</xsl:stylesheet>
And add more code. Hope it helped :)
Ok, after separation, this is a main.xsl . I just simplified here the variable value.
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml">
<xsl:output name="indent" method="html" indent="yes" omit-xml-declaration="yes"/>
<xsl:output name="no_indent" method="html" indent="no" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:variable name="indent" select="'yes'"/>
<xsl:if test="$indent='yes'">
<xsl:result-document format="indent" >
<xsl:call-template name="data"/>
</xsl:result-document>
</xsl:if>
<xsl:if test="$indent='no'">
<xsl:result-document format="no_indent" >
<xsl:call-template name="data"/>
</xsl:result-document>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
And next file, let's say 1.xsl
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
<xsl:import href="main.xsl"/>
<xsl:template name="data">
...
</xsl:template>
</xsl:stylesheet>
Here, I have an xsl transformation error

How to ignore namespaces during xsl translation time

I have an xml as below.
<?xml version="1.0" encoding="UTF-8"?>
<books xmlns="http://www.books.com/SRK">
<name>English</name>
</books
I required the following output after translation using xsl .
<?xml version="1.0" encoding="UTF-8"?>
<books>
<name>English</name>
</books>
I need an xsl to ignore the namespace.I have tried something but its not working with namespace.
I need your help.Your help would be appreciated.
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()[not(self::*)]">
<xsl:copy/>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
when applied to the provided XML document:
<books xmlns="http://www.books.com/SRK">
<name>English</name>
</books>
produces the wanted, correct result:
<books>
<name>English</name>
</books>
Its working only if i include the above templates if i add some other templates other than the above one then the translation is not at all working .None of the template getting executed.
Probably you are missing the declaration of the namespace for the book element. Example:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:b="http://www.books.com/SRK"
exclude-result-prefixes="b">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- #dimitre's answer templates -->
<xsl:template match="b:name">
<!-- your template for name -->
</xsl:template>
</xsl:stylesheet>
Moreover, make sure to use local-name() function to get the name of an element without the related namespace.
Example
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:b="http://www.books.com/SRK"
exclude-result-prefixes="b">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="b:input">
<xsl:element name="{local-name(.)}">
<xsl:apply-templates select="b:name"/>
</xsl:element>
</xsl:template>
<xsl:template match="b:name">
<xsl:element name="{local-name()}">
<xsl:value-of select="."/>
</xsl:element>
<lhs>
<xsl:apply-templates select="following-sibling::b:lhs/b:evaluate"/>
</lhs>
</xsl:template>
<xsl:template match="b:evaluate">
Something to evaluate...
</xsl:template>
</xsl:stylesheet>
gets:
<?xml version="1.0" encoding="UTF-8"?>
<input>
<name>English</name>
<lhs>
Something to evaluate...
</lhs>
</input>
Second Example
You can create a separate transform called local-identity.xsl containing #Dimitre solution. Then you can import it in your transform. Because you have a namespace, to match elements you must change all your XPaths including the prefix you will declare in the transform, as in the following example:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:brl="http://www.xyz.com/BRL"
exclude-result-prefixes="brl"
version="1.0">
<xsl:import href="local-identity.xsl"/>
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/brl:rule">
<!-- do your staff, select using brl prefix -->
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>