I am unable to figure it out how to build below XML using XSLT 1.0
<values>
<field name="abc"></field>
<field name="nch"></field>
</values>
there should not be any space between elements start and end tag.
Kindly help me as soon as possible.
Thanks.
In Saxon you have to change the output method to "html".
Example:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<values>
<field name="abc"></field>
<field name="nch"></field>
</values>
</xsl:template>
</xsl:stylesheet>
HereĀ“s a workearound that works for vs2010.
Example 1:
<?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" indent="yes"/>
<xsl:template match="/">
<values>
<field name="abc">
<xsl:value-of select="substring-before(' ',' ')"/>
</field>
<field name="nch">
<xsl:value-of select="substring-before(' ',' ')"/>
</field>
</values>
</xsl:template>
</xsl:stylesheet>
Example 2:
<?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" indent="yes"/>
<xsl:template match="/">
<xsl:element name="values">
<xsl:element name="filed">
<xsl:attribute name="name">abc</xsl:attribute>
<xsl:value-of select="substring-before(' ',' ')"/>
</xsl:element>
<xsl:element name="filed">
<xsl:attribute name="name">nch</xsl:attribute>
<xsl:value-of select="substring-before(' ',' ')"/>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Output:
<?xml version="1.0" encoding="utf-8"?>
<values>
<filed name="abc"></filed>
<filed name="nch"></filed>
</values>
The difference between <x></x> and <x/> is purely lexical and generally cannot be controlled by the XSLT processor, because the final output is performed by the Serializer.
With some XSLT processors (using their built-in serializers), it may be possible to output the full form of an empty element. However, with other processors, such as Saxon, this isn't (easily) possible.
Related
I want to remove namespace at output structure. I prepared XSLT code
but it gives namespace on this element
My Input XML is this.
<?xml version='1.0' encoding='UTF-8'?>
<n0:Messages xmlns:n0="http://sap.com/xi/XI">
<n0:Message>
<ContactData>
<Data>
<information>
<Name>A</Name>
<Phone>123456</Phone>
</information>
</Data>
</ContactData>
</n0:Message>
</n0:Messages>
XSLT CODE implemented
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:n0="http://sap.com/xi/XI" exclude-result-prefixes="n0">
<!-- Output -->
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select= "//ContactData"/>
</xsl:template>
<xsl:template match="//*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Present output:
<?xml version='1.0' encoding='UTF-8'?>
<ContactData xmlns:n0="http://sap.com/xi/XI">
<Data>
<information>
<Name>A</Name>
<Phone>123456</Phone>
</information>
</Data>
</ContactData>
Output expected
<?xml version='1.0' encoding='UTF-8'?>
<ContactData>
<Data>
<information>
<Name>A</Name>
<Phone>123456</Phone>
</information>
</Data>
</ContactData>
Please help on this code
Thank you very much.
If you're able to use XSLT 2.0, you can achieve the required output simply by:
<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:strip-space elements="*"/>
<xsl:template match="/">
<xsl:copy-of select="*/*/*" copy-namespaces="no"/>
</xsl:template>
</xsl:stylesheet>
Demo: https://xsltfiddle.liberty-development.net/3NSSEuK
In XSLT 1.0, it takes a bit more work:
<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:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates select="*/*/*" />
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Demo: https://xsltfiddle.liberty-development.net/3NSSEuK/1
Try this by using template * and # :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:n0="http://sap.com/xi/XI"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs math n0" version="1.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="/*:Messages/ContactData"/>
</xsl:template>
</xsl:stylesheet>
For the following xml document:
<company>
<employee>
<name>John Andrews</name>
<age>23</age>
<salary>4000</salary>
<division>Accounting</division>
</employee>
</company>
I have the xsl like
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:value-of select="company/employee/name"/>
<xsl:variable name="test">
<xsl:text>company/employee/name</xsl:text>
</xsl:variable>
<xsl:evaluate xpath="$test"/>
</xsl:template>
</xsl:stylesheet>
How can I use $test variable in xsl:evaluate in order to get the same result as in the:
<xsl:value-of select="company/employee/name"/>
Is it possible?
You need to set the context item with e.g.
<xsl:evaluate xpath="$test" context-item="."/>
The XML I am expecting is supposed to be only one url/urn (xmlns:urn="urn:123:456") like below:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:urn="urn:123:456"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl" exclude-result-prefixes="urn">
When used with the below namespace it's OK:
<Document xmlns="123:456" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
But recently I am receiving a different document with the same structure as before, only difference is the namespace like below:
<Document xmlns="789:123" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
My question is, is there any way that I can support both in the same XSLT file
Below is a sample of my XSLT file:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:urn="urn:123:456"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl" exclude-result-prefixes="urn">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/urn:Document">
<Profiles>
<xsl:apply-templates select="*"/>
</Profiles>
</xsl:template>
<xsl:template match="urn:File">
<File>
<FileId>
<xsl:value-of select="urn:Id"/>
</FileId>
<FileDate>
<xsl:value-of select="urn:Created"/>
</FileDate>
</File>
</xsl:template>
<xsl:template match="urn:Employee">
<Information>
<EmpName>
<xsl:value-of select="urn:Personal/Name"/>
</EmpName>
<Age>
<xsl:value-of select="urn:Personal/Age"/>
</Age>
.
.
.
</Information>
</xsl:template>
</xsl:stylesheet>
You could declare both namespaces, e.g.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns1="urn:123:456"
xmlns:ns2="urn:789:123"
exclude-result-prefixes="ns1 ns2">
Then use a union expression for your matches and selections, for example:
<xsl:template match="/ns1:Document | /ns2:Document">
Want to add an xmlns declaration to the root only and I use this xml:
<Message>
</Message>
and xslt:
<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="/">
<xsl:element name="Element1" namespace="http://www.blablabla.com">
<xsl:element name="Element2">
<xsl:element name="Element3">Hmm</xsl:element>
</xsl:element>
<xsl:element name="Element4">
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The result is:
<Element1 xmlns="http://www.blablabla.com">
<Element2 xmlns="">
<Element3>Hmm</Element3>
</Element2>
<Element4 xmlns=""/>
</Element1>
I want only Element1 to have xmlns not the Element2, 4 or others.
I can make this way but that means to write for each element the variable name:
<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:variable name="vNS"
select="'http://www.blablabla'"/>
<xsl:template match="/">
<xsl:element name="Element1" namespace="{$vNS}">
<xsl:element name="Element2" namespace="{$vNS}">
<xsl:element name="Element3" namespace="{$vNS}">Hmm</xsl:element>
</xsl:element>
<xsl:element name="Element4" namespace="{$vNS}">
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
How to do it?
Thanks.
Using xsl:element with namespaces requires you to indicate for all elements in which namespace they belong. It is easier to avoid using xsl:element when dealing with namespaces.
For example:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:bla="http://www.blablabla.com">
<xsl:output method="xml" version="1.0" encoding="UTF-8" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<bla:Element1>
<Element2>
<Element3>Hmm</Element3>
</Element2>
<Element4 />
</bla:Element1>
</xsl:template>
</xsl:stylesheet>
This will create the required namespace on only the first element. You just have to declare the namespace into the stylesheet declaration and then you can use this namespace directly in the elements. Also your XSLT is more readable when avoiding xsl:element.
I want to achieve this using XSLT 1.0. Hours is represented in Hours and minutes(for ex: 10:30 is basically 10 hours 30 minutes). I need to convert it into only hours(10.50) and then calculate the sum of all hours nodes.
Here is a source XML document:
<Record>
<hours>10:30</hours>
<hours>20:30</hours>
<hours>10:60</hours>
</Record>
Output:
<Record>
<TotalHours>42.0</TotalHours>
</Record>
Do note that the solution in Joepie's answer causes compile-time syntax error in any compliant XSLT 1.0 processor (it can only be executed without compilation errors if one uses an XSLT 2.0 processor):
SAXON 6.5.4 from Michael Kay
Java version 1.6.0_31
Error at xsl:value-of on line 11 of file:/(Untitled):
Error in expression sum(hours/number(substring-before(., ':'))) + sum(hours/number(substring-after(., ':'))) div 60 : Unexpected token [<function>] in path expression
Transformation failed: Failed to compile stylesheet. 1 error detected.
Press any key to continue . . .
Here is a truly working, true XSLT 1.0 solution:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:copy>
<xsl:variable name="vrtfTimes">
<xsl:for-each select="*">
<t>
<xsl:value-of select=
"substring-before(., ':') + substring-after(.,':') div 60"/>
</t>
</xsl:for-each>
</xsl:variable>
<TotalHours>
<xsl:value-of select="floor(sum(ext:node-set($vrtfTimes)/*))"/>
</TotalHours>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<Record>
<hours>10:30</hours>
<hours>20:30</hours>
<hours>10:60</hours>
</Record>
the wanted, correct result is produced:
<Record>
<TotalHours>42</TotalHours>
</Record>
Note:
In case you want to get not only the hours from the sum, but also the remaining minute -- as minutes:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:copy>
<xsl:variable name="vrtfTimes">
<xsl:for-each select="*">
<t>
<xsl:value-of select=
"substring-before(., ':') + substring-after(.,':') div 60"/>
</t>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="vSum" select="sum(ext:node-set($vrtfTimes)/*)"/>
<TotalHours>
<xsl:value-of select="floor($vSum)"/>
<xsl:text>:</xsl:text>
<xsl:value-of select="round(60* ($vSum - floor($vSum)))"/>
</TotalHours>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following (slightly more complex) XML document:
<Record>
<hours>10:30</hours>
<hours>20:30</hours>
<hours>10:60</hours>
<hours>1:15</hours>
<hours>1:03</hours>
</Record>
the correct result is produced:
<Record>
<TotalHours>44:18</TotalHours>
</Record>
In XSLT 1.0:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="Record">
<Record>
<TotalHours>
<xsl:value-of select="
sum(hours/number(substring-before(., ':'))) +
sum(hours/number(substring-after(., ':'))) div 60
"/>
</TotalHours>
</Record>
</xsl:template>
</xsl:transform>
Working example
If you also want the minutes in stead of an fraction of an hour:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="Record">
<Record>
<TotalHours>
<xsl:value-of select="
concat(
sum(hours/number(substring-before(., ':'))) + floor(sum(hours/number(substring-after(., ':'))) div 60),
'.',
format-number(floor(sum(hours/number(substring-after(., ':'))) mod 60), '00')
)
"/>
</TotalHours>
</Record>
</xsl:template>
</xsl:transform>
**Working example