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')" />
Related
I want to check to contain only characters + space and <p> nodes inside <used>.
Input:
<root>
<used><p>String 1</p></used>
<used>string 2<p>string 3</p></used>
<used>string 4</used>
<used><image>aaa.jpg</image>para</used>
The output should be:
<ans>
<abc>string 1</abc>
<abc>string 4</abc>
</ans>
Tried code:
<ans>
<abc>
<xsl:template match="root">
<xsl:choose>
<xsl: when test="getCode/matches(text(),'^[a-zA-Z0-9]+$')">
<xsl:text>text()</xsl:text>
</xsl:when>
</xsl:choose>
</xsl:template>
</abc>
</ans>
My tried code is not working as I am expecting. How can I fix this? Thank you. I am using XSLT 2.0
You can use the following XSLT-2.0 stylesheet to get the desired result:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl= "http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<!-- Handle the <root> element -->
<xsl:template match="/root">
<ans>
<xsl:apply-templates select="used" />
</ans>
</xsl:template>
<!-- Create <abc> elements for every matching element -->
<xsl:template match="used[not(*) and matches(text(),'^[\sa-zA-Z0-9]+$')] | used[not(text()) and matches(p/text(),'^[\sa-zA-Z0-9]+$')]/p">
<abc><xsl:copy-of select="text()" /></abc>
</xsl:template>
<!-- Remove all spurious text nodes -->
<xsl:template match="text()" />
</xsl:stylesheet>
Its result is
<?xml version="1.0" encoding="UTF-8"?>
<ans>
<abc>String 1</abc>
<abc>string 4</abc>
</ans>
I have this xsl path that gives me a desired value:
/path/to/#value
Is there a way to combine this into a substring?
substring(/path/to/#value, 1, 5)
The preceding statement does not work because I'm not as familiar to xsl as I thought
Actually, it should work just fine:
XML:
<?xml version='1.0'?>
<path>
<to value='123456'/>
</path>
XSLT:
<?xml version="1.0"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:template match="/">
<out>
<xsl:value-of select='substring(/path/to/#value, 1, 5)'/>
</out>
</xsl:template>
</xsl:stylesheet>
Another way is to use an intermediate variable:
<xsl:variable name='t' select='/path/to/#value'/>
<xsl:value-of select='substring( $t, 1, 5 )'/>
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.
assuming that I have following xml:
<ns5:OrderTotal>
<ns5:Name>AmountPaid</ns5:Name>
<ns5:Description>Payment Received</ns5:Description>
<ns5:SortOrder>4</ns5:SortOrder>
<ns5:Value>16.95</ns5:Value>
</ns5:OrderTotal>
<ns5:OrderTotal>
<ns5:Name>AmountDue</ns5:Name>
<ns5:Description>Current Amount Due</ns5:Description>
<ns5:SortOrder>5</ns5:SortOrder>
<ns5:Value>0.0</ns5:Value>
</ns5:OrderTotal>
If I only want print the Value of the OrderTotal when it Name is AmountPaid, how could achieve this?
Thank you for the helps.
I don't know how you are going to print the value you need, but it can be gathered using the following XPath expression:
//ns5:OrderTotal[child::ns5:Name = 'AmountPaid']/ns5:Value
For example:
XML:
<ns5:Orders xmlns:ns5="a">
<ns5:OrderTotal>
<ns5:Name>AmountPaid</ns5:Name>
<ns5:Description>Payment Received</ns5:Description>
<ns5:SortOrder>4</ns5:SortOrder>
<ns5:Value>16.95</ns5:Value>
</ns5:OrderTotal>
<ns5:OrderTotal>
<ns5:Name>AmountDue</ns5:Name>
<ns5:Description>Current Amount Due</ns5:Description>
<ns5:SortOrder>5</ns5:SortOrder>
<ns5:Value>0.0</ns5:Value>
</ns5:OrderTotal>
</ns5:Orders>
XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" version="1.0"
xmlns:ns5="a">
<xsl:template match="/">
<xsl:element name="Value">
<xsl:value-of select="//ns5:OrderTotal[child::ns5:Name = 'AmountPaid']/ns5:Value"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Output:
<?xml version="1.0" encoding="utf-8"?>
<Value>16.95</Value>
<xsl:if test="Name = 'AmountPaid'">
<xsl:value-of select="Value"/>
</xsl:if>
Try the above XSL.
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().