I'm having some difficulty with the format-number function.
Given this XML
<testvalues>
<test value="02.25"/>
<test value="02.2"/>
<test value="02.20"/>
</testvalues>
I am trying to produce this output
<testvalues>
<test>02.25</test>
<test>02.2</test>
<test>02.20</test>
</testvalues>
But I can't find a picture-string do do that.
Given this xslt
<?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="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="testvalues">
<xsl:copy>
<xsl:apply-templates mode="by-1d"/>
<xsl:apply-templates mode="by-1plus1d"/>
<xsl:apply-templates mode="by-2d"/>
</xsl:copy>
</xsl:template>
<xsl:template match="test" mode="by-1d">
<xsl:copy>
<xsl:value-of select="format-number(#value,'00.0')"/>
</xsl:copy>
</xsl:template>
<xsl:template match="test" mode="by-1plus1d">
<xsl:copy>
<xsl:value-of select="format-number(#value,'00.0#')"/>
</xsl:copy>
</xsl:template>
<xsl:template match="test" mode="by-2d">
<xsl:copy>
<xsl:value-of select="format-number(#value,'00.00')"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
the output created is
<?xml version="1.0" encoding="UTF-8"?>
<testvalues>
<test>02.2</test>
<test>02.2</test>
<test>02.2</test>
<test>02.25</test>
<test>02.2</test>
<test>02.2</test>
<test>02.25</test>
<test>02.20</test>
<test>02.20</test>
</testvalues>
The trailing zeros do not match the the incoming digits.
'00.00' will force 2 trailing digit
'00.0' will trim to one trailing digit
'00.0#' will force 2 digits except where 2nd digit is zero when it trims to 1 digit
I want to print just 1 trailing digit where the input is 1 trailing digit, but 2 digits (including zero) where the input has >1 trailing digit.
Is that possible?
I want to print just 1 trailing digit where the input is 1 trailing digit, but 2 digits (including zero) where the input has >1 trailing digit.
To do exactly that, you could use:
<xsl:template match="test">
<xsl:copy>
<xsl:value-of select="format-number(#value, if(string-length(substring-after(#value, '.')) > 1) then'00.00' else '00.0')"/>
</xsl:copy>
</xsl:template>
Given the input of:
XML
<testvalues>
<test value="02"/>
<test value="02.2"/>
<test value="02.20"/>
<test value="02.200"/>
<test value="02.2000"/>
<test value="02.20002"/>
</testvalues>
this would produce:
Result
<?xml version="1.0" encoding="UTF-8"?>
<testvalues>
<test>02.0</test>
<test>02.2</test>
<test>02.20</test>
<test>02.20</test>
<test>02.20</test>
<test>02.20</test>
</testvalues>
Demo: https://xsltfiddle.liberty-development.net/nbBfrFy/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 an XML and I am looking for finding particular tag (in this case "FirstName") and removing space in the value only if there is a - character before the space.
In other words, I want to keep spaces if there is no - front of them. I want to do this using an XSL stylesheet with RegEx matching and replace function.
Expected result is Sam-Louise, removing space between "Sam-" and "Louise"
<?xml version="1.0" encoding="utf-8"?>
<NCV Version="1.14">
<Invoice>
<customer>
<customerId>12785</customerId>
<FirstName>Sam- Louise</FirstName>
<LastName>Jones</LastName>
</customer>
</Invoice>
</NCV>
This is one possible XSLT :
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="FirstName">
<FirstName>
<xsl:value-of select="replace(., '-\s+', '-')"/>
</FirstName>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:transform>
xsltransform.net demo
output :
<NCV Version="1.14">
<Invoice>
<customer>
<customerId>12785</customerId>
<FirstName>Sam-Louise</FirstName>
<LastName>Jones</LastName>
</customer>
</Invoice>
</NCV>
You can use following RegEx in match
(\<FirstName\>.*?-)\s+
And replace it with the first captured group $1
RegEx (\<FirstName\>.*?-)\s+ matches,
\<FirstName\>.*?-: Literal <FirstName> followed by any character non-greedy, until first hyphen is found. This match is added in the captured group.
\s+: Match one or more of the space characters.
By replacing it with $1, will remove the spaces after hyphen.
I've got some XML that has an Alphabetically ordered list of strings. I want to generate a set of Divs containing the first letter of each set with no duplicate first letters.
XML
<?xml version="1.0" encoding="UTF-8"?>
<textstring>
<example>Delta</example>
<example>delta2</example>
<example>harmony</example>
<example>incognito</example>
<example>Inconvenient</example>
</textstring>
XSL
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="textstring">
<xsl:apply-templates mode="trick" select="/textstring/example"/>
</xsl:template>
<xsl:template match="/textstring/example" mode="trick">
<xsl:variable name="firstLetter" select="substring(text(),1,1)"/>
<div>
<xsl:copy-of select="$firstLetter"/>
</div>
</xsl:template>
</xsl:stylesheet>
Output
D
d
h
i
I
Desired Output
D
H
I
I was thinking of something that would add to the select such as
<xsl:template match="textstring">
<xsl:apply-templates mode="trick" select="/textstring/example[not(starts-with(
substring(
translate(text(),
'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') ,1,1),
substring(following-sibling::example[
translate(text(),
'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') ],1,1)
))]"/>
</xsl:template>
But that results in
D
d
h
Am I completely off base? I didn't really want to switch to a for-each loop since it is somewhat resource intensive, but is checking preceding sibling really any less so?
As told in the comment you should use the Muenchian Method. See the next XSLT:
<?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" encoding="UTF-8" indent="yes"/>
<xsl:key name="first-letters" match="example" use="substring(translate(., 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 1, 1)" />
<xsl:template match="#*|node()">
<xsl:apply-templates select="#*|node()" />
</xsl:template>
<xsl:template match="textstring">
<xsl:apply-templates select="example[generate-id() = generate-id(key('first-letters', substring(translate(., 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 1, 1))[1])]" />
</xsl:template>
<xsl:template match="example">
<div>
<xsl:value-of select="substring(translate(., 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 1, 1)" />
</div>
</xsl:template>
</xsl:stylesheet>
This will generate the required output:
<div>D</div>
<div>H</div>
<div>I</div>
I need to make certain modifications to my XML input, depending on certain conditions. I am using XSLT 1.0.
the value of the message_type element (child element of m_cotrol) should be changed
A new element message_status should be added (as a child of the m_control element).
These changes are reflected in the expected output XML. With my current XSLT code, I am only able to achieve the second requirement.
Input XML:
<?xml version="1.0"?>
<message xmlns="http://www.origoservices.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<m_control>
<control_timestamp>2013-04-12T09:24:38.902</control_timestamp>
<message_id>a50ec030-72ab</message_id>
<retry_number>0</retry_number>
<message_type>Request</message_type>
<message_version>test.XSD</message_version>
<expected_response_type>synchronous</expected_response_type>
<initiator_id>FST</initiator_id>
<initiator_orchestration_id>1637280</initiator_orchestration_id>
<responder_id>mycomp</responder_id>
</m_control>
<m_content>
<b_control>
<service_provider_reference_number>650971</service_provider_reference_number>
<intermediary_case_reference_number>Sample1</intermediary_case_reference_number>
<quote_type>Comparison</quote_type>
<quote_or_print>Print</quote_or_print>
<message_version_number>3.7</message_version_number>
<submission_date>0001-04-12</submission_date>
</b_control>
</m_content>
</message>
Expected Output:
<message xmlns="http://www.origoservices.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<m_control>
<control_timestamp>2013-04-12T09:24:38.902</control_timestamp>
<message_id>a50ec030-72ab</message_id>
<retry_number>0</retry_number>
<message_type>Response</message_type>
<message_version>test.XSD</message_version>
<expected_response_type>synchronous</expected_response_type>
<initiator_id>FST</initiator_id>
<initiator_orchestration_id>1637280</initiator_orchestration_id>
<responder_id>mycomp</responder_id>
<message_status>User not allowed access</message_status>
</m_control>
<m_content>
<b_control>
<service_provider_reference_number>650971</service_provider_reference_number>
<intermediary_case_reference_number>Sample1</intermediary_case_reference_number>
<quote_type>Comparison</quote_type>
<quote_or_print>Print</quote_or_print>
<message_version_number>3.7</message_version_number>
<submission_date>0001-04-12</submission_date>
<quote_response_status>Error</quote_response_status>
<quote_error_note>
<reason>[Error] Check if the User has access to the requested service</reason>
</quote_error_note>
</b_control>
</m_content>
</message>
XSLT code: Based on the value of DataPower variable (var://service/error-message), I need the expected output.
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dp="http://www.datapower.com/extensions" version="1.0" extension-element-prefixes="dp" exclude-result-prefixes="dp">
<xsl:output method="xml" encoding="UTF-8"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//*[contains(name(),'m_control')]">
<xsl:choose>
<xsl:when test="dp:variable('var://service/error-message') = 'not present'">
<m_control xmlns="http://www.origoservices.com">
<xsl:apply-templates select="#* | *"/>
<message_status>User not recognized</message_status>
</m_control>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="//*[contains(name(),'b_control')]">
<xsl:choose>
<xsl:when test="dp:variable('var://service/error-subcode')='0x01d30002'">
<b_control xmlns="http://www.origoservices.com">
<xsl:apply-templates select="#* | *"/>
<quote_response_status>Error</quote_response_status>
<quote_error_note>
<reason>[Error] Check if the User has access to the requested service</reason>
</quote_error_note>
</b_control>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
The following stylesheet meets both of your requirements. It does a common identity transform (which your XSLT does, too) with exceptions.
Note that I have not taken into consideration any changes that are performed by your stylesheet but not listed as a requirement (i.e. changing quote_error_note and quote_response_status).
This line:
<xsl:template match="text()[parent::ori:message_type]">
meets your first requirement, the one you were unable to code. It matches the text content of message_type and outputs "Response" instead.
But this solution differs from yours in another way: it does not match elements along the lines of:
<xsl:template match="//*[contains(name(),'m_control')]">
Rather, their correct namespace is identified:
<xsl:template match="ori:m_control">
Now, what's the difference? Your way of describing the template match allows elements of any namespace to be matched. This might not be a problem in your case (no conflicting namespaces) but it could be one in general.
Full stylesheet
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ori="http://www.origoservices.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exclude-result-prefixes="ori xsi">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ori:m_control">
<xsl:copy>
<xsl:apply-templates/>
<message_status>
<xsl:text>User not allowed access</xsl:text>
</message_status>
</xsl:copy>
</xsl:template>
<xsl:template match="text()[parent::ori:message_type]">
<xsl:text>Response</xsl:text>
</xsl:template>
</xsl:stylesheet>
Given the following fragment:
<recipe>
get a bowl
<ingredient>flour</ingredient>
<ingredient>milk</ingredient>
mix it all together!
</recipe>
How can I match "get a bowl" and "mix it all together!" and wrap them in another element to create the following?
<recipe>
<action>get a bowl</action>
<ingredient>flour</ingredient>
<ingredient>milk</ingredient>
<action>mix it all together!</action>
</recipe>
You could define a template matching text nodes that are a direct child of recipe:
<xsl:template match="recipe/text()">
<action><xsl:value-of select="normalize-space()" /></action>
</xsl:template>
Full XSLT example:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*" />
<xsl:output method="xml" indent="yes" />
<xsl:template match="#*|node()">
<xsl:copy><xsl:apply-templates select="#*|node()" /></xsl:copy>
</xsl:template>
<xsl:template match="recipe/text()">
<action><xsl:value-of select="normalize-space()" /></action>
</xsl:template>
</xsl:stylesheet>
Note that the normalize-space() is required, even with the xsl:strip-space - that only affects text nodes that contain only whitespace, it doesn't strip off leading and trailing space from nodes that contain any non-whitespace characters. If you had
<action><xsl:value-of select="." /></action>
then the result would be something like
<recipe>
<action>
get a bowl
</action>
<ingredient>flour</ingredient>
<ingredient>milk</ingredient>
<action>
mix it all together!
</action>
</recipe>