Hello folks,
I am trying to set a fixed value to a tag in XML on comparing to a value in condition. such as
<xsl:when test="(//TestInput='XYZA') OR (//TestInput='XYZB') OR (//TestInput='XYZC') OR (//TestInput='XYZD')">abcd</xsl:when>
when i trying to run the transformation with an XML with tag <TestInput>, it is giving me an error as
Extra illegal tokens: '(', '/', '/', 'TestInput', '=', ''XYZA'', ')', 'OR', '(', '/', '/', 'TestInput', '=', ''XYZB'', ')', 'OR', '(', '/', '/', 'TestInput', '=', ''XYZC'', ')', 'OR', '(', '/', '/', 'TestInput', '=', ''XYZD'', ')'
Please help me out in setting the value to this tag based on condition using OR operator in where clause.
Thanks in Advance
Case matters with XML/XSLT/XPath so use or instead of OR.
I created a test with the following XML:
<?xml version="1.0" encoding="utf-8"?>
<Test>
<Item>DAC</Item>
<Item>DAD</Item>
<Item>DAE</Item>
</Test>
And the following XSLT:
<?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"/>
<xsl:template match="#* | node()">
<test>
<xsl:choose>
<xsl:when test="//Item[text()='DAC'] or //Item[text()='DAE']">
<output>Here is the text!</output>
</xsl:when>
<xsl:otherwise></xsl:otherwise>
</xsl:choose>
</test>
</xsl:template>
</xsl:stylesheet>
I get the following output:
<?xml version="1.0" encoding="utf-8"?>
<test>
<output>Here is the text!</output>
</test>
Tested with Micorosft.Net's XmlDocument class. The critical difference is the case of the 'or' statement.
The problem is that //TestInput selects a set of elements instead of just one.
You should use xsl:for-each
<xsl:for-each select="//TestInput[.='a'or'b'or'c']">abc</xsl:for-each>
Related
I want yo get the first name initial and last name.
Input :
<root>
<ele name="Samp Huwani"/>
<ele name="Laura McKay (J)"/>
<ele name="Dery Wertnu"/>
</root>
Output
<names>S Huwani</name>
<names>L McKay (J)</name>
<names>D Wertnu</name>
Tried Code:
<xsl:template match="root/ele">
<names>
<xsl:value-of select="replace(#name, '^(.{1}).* (.*)', '$1 $2')" />
</name>
</xsl:template>
Result I am getting:
<names>S Huwani</name>
<names>L (J)</name>
<names>D Wertnu</name>
According to my code, I am getting L (J). it should be L McKay (J). But Other two results are working as expected
I am using XSLT 2.0. Thank you
You can use substring and substring-after:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="root/ele">
<names>
<xsl:value-of select="concat(substring(#name, 1, 1), ' ', substring-after(#name, ' '))"/>
</names>
</xsl:template>
</xsl:stylesheet>
If you want to use regex for this, try:
<xsl:value-of select="replace(#name, '^(.{1})[^ ]* (.*)', '$1 $2')" />
I am dealing with below XML where I need to remove a special character in firstname. é in (Andrés) not sure what is this character is actually called. If I process firstname as is it's failing in the Vendor system
<?xml version="1.0" encoding="UTF-8"?>
<reportentry>
<reportdata>
<id>12345</id>
<firstname>Andrés</firstname>
<lastname>Williams</lastname>
</reportdata>
</reportentry>
I simply tried replace function which is working, below is the code. Not sure is there any better way to deal with it ? any suggestions ?
<xsl:value-of select="replace($string1, 'é', 'e')"/>
Full code
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
<xsl:variable name="string1" select="/reportentry/reportdata/firstname"/>
<xsl:variable name="comma" select="','"/>
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:template match="/reportentry">
<xsl:value-of select="reportdata/id"/>
<xsl:value-of select="$comma"/>
<xsl:value-of select="replace($string1, 'é', 'e')"/>
<xsl:value-of select="$comma"/>
<xsl:value-of select="reportdata/lastname"/>
</xsl:template>
</xsl:stylesheet>
I expected result as 12345,Andres,Williams
You can strip most diacritics by using normalize-unicode() to convert the string to decomposed normal form (NFD), and then using replace() to remove all "non-spacing mark" characters (category Mn).
So replace(normalize-unicode(xxx, 'NFD'), '\p{Mn}', '')
Not tested.
But it would be better to modernise the receiving application so it can handle international names...
How to change all decimal value to zeroes in XSL
Example value:
from : 9876.123
to : 9876.000
Well,
floor(9876.123)
returns:
9876
and:
format-number(floor(9876.123), '#.000')
returns:
9876.000
I don't see why this would be useful, but in case you do want to preserve the number of decimal places, I would use:
format-number(floor($amount), translate($amount, '123456789', '000000000'))
In case the number of digits after the decimal point is unknown in advance, use:
concat(substring-before(., '.'),
'.',
translate(substring-after(., '.'), '123456789', '000000000'))
Here is a complete XSLT transformation example:
<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="d">
<xsl:value-of select=
"concat(substring-before(., '.'),
'.',
translate(substring-after(.,'.'), '123456789','000000000'))"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<t>
<d>9876.1</d>
<d>9876.12</d>
<d>9876.123</d>
<d>9876.1234</d>
<d>9876.12345</d>
<d>9876.123456</d>
<d>9876.1234567</d>
<d>9876.12345678</d>
<d>9876.123456789</d>
</t>
the wanted, correct result is produced:
9876.0
9876.00
9876.000
9876.0000
9876.00000
9876.000000
9876.0000000
9876.00000000
9876.000000000
Update
Someone requested that integer values (not containing decimal point) are also processed correctly (copied intact).
I also added to this that negative values and / or currency denominations should also be processed correctly.
Although this falls outside the scope of the current problem, here is again a single XPath 1.0 expression that produces the wanted result:
concat(substring-before(concat(., '.'), '.'),
translate(., '+-$0123456789', ''),
translate(substring-after(.,'.'), '123456789','000000000'))
And here again is the complete transformation:
<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="d">
<xsl:value-of select=
"concat(substring-before(concat(., '.'), '.'),
translate(., '+-$0123456789', ''),
translate(substring-after(.,'.'), '123456789','000000000'))"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<t>
<d>-$1.234</d>
<d>-1.234</d>
<d>-.234</d>
<d>9876</d>
<d>9876.1</d>
<d>9876.12</d>
<d>9876.123</d>
<d>9876.1234</d>
<d>9876.12345</d>
<d>9876.123456</d>
<d>9876.1234567</d>
<d>9876.12345678</d>
<d>9876.123456789</d>
</t>
the wanted, correct result is produced:
-$1.000
-1.000
-.000
9876
9876.0
9876.00
9876.000
9876.0000
9876.00000
9876.000000
9876.0000000
9876.00000000
9876.000000000
Consider the following XSL transformation:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:dyn="http://exslt.org/dynamic"
extension-element-prefixes="dyn">
<xsl:variable name="_raw">
<test>1</test>
<test>2</test>
</xsl:variable>
<xsl:variable name="list" select="exsl:node-set($_raw)"/>
<xsl:template match="/">
<result>
<xsl:for-each select="$list/test">
<loop>
<xsl:value-of select="dyn:evaluate('exsl:node-set($list)/test')"/>
</loop>
</xsl:for-each>
</result>
</xsl:template>
</xsl:transform>
Executing this on any input gives:
<?xml version="1.0" encoding="UTF-8"?>
<result xmlns:exsl="http://exslt.org/common">
<loop>1</loop>
<loop/>
</result>
What I don't understand is:
The esxl:note-set() inside dyn:evaluate() is necessary if I want to reference $list in the XPath string. Otherwise, the first <loop> is also empty. Why? $list is already a node set.
It's exactly the same code executed twice. Why does it yield no result the second time?
This works if I don't take the values from $list, but from the XML input instead. Where's the difference?
If I remove the <xsl:for-each>, dyn:evaluate() works without the exsl:node-set() in it. Why? There's no reference to the context in the expression that is evaluated, it shouldn't make a difference.
My XSLT processor is Xalan 2.7.2.
I believe what you want to do is:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:dyn="http://exslt.org/dynamic"
extension-element-prefixes="exsl dyn">
<xsl:variable name="_raw">
<test>1</test>
<test>2</test>
</xsl:variable>
<xsl:variable name="list" select="exsl:node-set($_raw)"/>
<xsl:template match="/">
<result>
<xsl:for-each select="$list/test">
<loop>
<xsl:value-of select="dyn:evaluate(.)"/>
</loop>
</xsl:for-each>
</result>
</xsl:template>
</xsl:transform>
Which will result in:
<?xml version="1.0" encoding="UTF-8"?>
<result><loop>1</loop><loop>2</loop></result>
Edit:
I am still not sure what you are after here, but let me point out a few details:
It's exactly the same code executed twice. Why does it yield no result
the second time?
That may be a bug in Xalan. If you run your code with libxslt, the result will be:
<?xml version="1.0"?>
<result xmlns:exsl="http://exslt.org/common"><loop>1</loop><loop>1</loop></result>
The esxl:note-set() inside dyn:evaluate() is necessary if I want to
reference $list in the XPath string. Otherwise, the first is
also empty. Why? $list is already a node set.
I don't think it's necessary. Or perhaps I don't understand what it's necessary for. In any case, changing this:
<loop>
<xsl:value-of select="dyn:evaluate('exsl:node-set($list)/test')"/>
</loop>
to:
<loop>
<xsl:value-of select="dyn:evaluate('$list/test')"/>
</loop>
will result in:
<?xml version="1.0" encoding="UTF-8"?>
<result xmlns:exsl="http://exslt.org/common"><loop>1</loop><loop>1</loop></result>
and this time the result is same for both Xalan and libxslt.
Given a node, eg.
<SI elem1="TI" elem2="FN" elem3="4099450222" elem4="TM" elem5="4094110000" elem6="MT" elem7="SP" elem8="MC" elem9="DS" elem10="DA" elem11="16"/>
I need my output to be "DA" if any attribute is "DA", or the value of the next attribute if any attribute is "BA" (i.e. if elem7="BA elem8="03" I want "03" output)
There is no danger of multiple matches, so if an attribute is "BA", there will be no "DA" attribute, but the values could occur in any element
I've looked into the attribute:: tag, but I'm not sure if this will fulfil my needs.
any help greatly appreciated
I made an assumption that your attributes has names in form of elemN where N = 1,2,3...,
and they are ordered accordingly.
The following XSLT:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="text" />
<xsl:template match="/SI">
<xsl:choose>
<xsl:when test="some $i in #* satisfies $i='DA'">
<xsl:text>DA</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="attr" select="concat('elem', xs:decimal(substring-after(#*[.='BA']/name(), 'elem')) + 1)" />
<xsl:value-of select="#*[name() = $attr]" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
applied to the following input XML:
<?xml version="1.0" encoding="UTF-8"?>
<SI elem1="TI" elem2="FN" elem3="4099450222" elem4="TM" elem5="4094110000" elem6="MT" elem7="SP" elem8="MC" elem9="DS" elem10="DA" elem11="16" />
gives DA as the output.
And applied to the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<SI elem1="TI" elem2="FN" elem3="4099450222" elem4="TM" elem5="4094110000" elem6="MT" elem7="BA" elem8="03" elem9="DS" elem10="DAs" elem11="16" />
gives 03 as the output.
EDIT
Here's the XSLT 1.0 version (tested under Altova XMLSpy):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:template match="/">
<xsl:apply-templates select="SI/#*" />
</xsl:template>
<xsl:template match="#*">
<xsl:choose>
<xsl:when test=". = 'DA'">
<xsl:text>DA</xsl:text>
</xsl:when>
<xsl:when test=".='BA'">
<xsl:variable name="attr" select="concat('elem', substring-after(name(), 'elem') + 1)" />
<xsl:value-of select="/SI/#*[name() = $attr]" />
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
I need my output to be "DA" if any attribute is "DA", or the value of
the next attribute if any attribute is "BA" (i.e. if elem7="BA
elem8="03" I want "03" output)
There is no danger of multiple matches, so if an attribute is "BA",
there will be no "DA" attribute, but the values could occur in any
element
This single XPath expression produces the wanted value:
string(/*/#*[. = 'DA']
|
/*/#*[name()
=
concat('elem', substring-after(name(/*/#*[.='BA']), 'elem') +1)]
)
And here is the complete transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:copy-of select=
"string(/*/#*[. = 'DA']
|
/*/#*[name()
=
concat('elem', substring-after(name(/*/#*[.='BA']), 'elem') +1)]
)"/>
</xsl:template>
</xsl:stylesheet>
As can be seen this transformation simply evaluates the XPath expression and copies the result of the evaluation to the output.
When the transformation is applied on this XML document (your 2nd case):
<SI elem1="TI"
elem2="FN"
elem3="4099450222"
elem4="TM"
elem5="4094110000"
elem6="MT"
elem7="BA"
elem8="03"
elem9="DS"
elem10="DD"
elem11="16"/>
the result is:
03
When the same transformation is applied on the originally provided XML document (your 1st case):
<SI elem1="TI"
elem2="FN"
elem3="4099450222"
elem4="TM"
elem5="4094110000"
elem6="MT"
elem7="SP"
elem8="MC"
elem9="DS"
elem10="DA"
elem11="16"/>
again the wanted, correct result is produced:
DA
Explanation:
Proper use of the XPath union operator |, and the functions string(), substring-after(), name() and `concat().