in xslt match decimal with in text and write after it - html

I have a problem. I think it is simple but I havent found it.
like below code I want to find and match multiplier factor value like "0.05" with "005" in the note value dynamically and take text "AAA" after "_ 005 _"(without spaces) and write it and others too.
I tried to use together both format number and concatenate to "concat(format-number(***))" but failed because of newby about this.
<cbc:Note>40.00 BT</cbc:Note>
<cbc:Note>17_ 2005.00</cbc:Note>
<cbc:Note>11_005_AAA</cbc:Note>
<cbc:Note>11_002_BBB</cbc:Note>
<cbc:Note>11_003_CCC</cbc:Note>
<cbc:InvoicedQuantity unitCode="CS">1.000</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="TRY">200.00</cbc:LineExtensionAmount>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:MultiplierFactorNumeric>0.03</cbc:MultiplierFactorNumeric>
<cbc:Amount currencyID="TRY">6.00</cbc:Amount>
<cbc:BaseAmount currencyID="TRY">200.00</cbc:BaseAmount>
</cac:AllowanceCharge>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:MultiplierFactorNumeric>0.05</cbc:MultiplierFactorNumeric>
<cbc:Amount currencyID="TRY">10.00</cbc:Amount>
<cbc:BaseAmount currencyID="TRY">200.00</cbc:BaseAmount>
</cac:AllowanceCharge>
current xslt block
<xsl:for-each select="./cac:AllowanceCharge/cbc:MultiplierFactorNumeric">
<br/>
<xsl:text> %</xsl:text>
<xsl:value-of select="format-number(. * 100, '###.##0,00', 'european')"/>,
</xsl:for-each>
I appreciate if you help me.

It is very difficult to understand your question.
The following minimal example is mostly based on a guess. It formats the MultiplierFactorNumeric value as a 3-digit whole number and uses it as a key to retrieve the corresponding Note value:
XML
<root>
<Note>40.00 BT</Note>
<Note>17_ 2005.00</Note>
<Note>11_005_AAA</Note>
<Note>11_002_BBB</Note>
<Note>11_003_CCC</Note>
<AllowanceCharge>
<MultiplierFactorNumeric>0.03</MultiplierFactorNumeric>
</AllowanceCharge>
<AllowanceCharge>
<MultiplierFactorNumeric>0.05</MultiplierFactorNumeric>
</AllowanceCharge>
</root>
XSLT 1.0
<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:key name="note" match="Note" use="substring-before(substring-after(., '_'), '_')" />
<xsl:template match="/root">
<result>
<xsl:for-each select="AllowanceCharge">
<item>
<factor>
<xsl:value-of select="MultiplierFactorNumeric"/>
</factor>
<value>
<xsl:value-of select="substring-after(substring-after(key('note', format-number(100*MultiplierFactorNumeric, '000')), '_'), '_')"/>
</value>
</item>
</xsl:for-each>
</result>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<result>
<item>
<factor>0.03</factor>
<value>CCC</value>
</item>
<item>
<factor>0.05</factor>
<value>AAA</value>
</item>
</result>

Related

XSLT convert HTML special characters despite output method is html

I have the following xml file:
<?xml version="1.0" encoding="UTF-8"?>
<record
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd"
xmlns="http://www.loc.gov/MARC21/slim">
....
<datafield tag="856" ind1=" " ind2=" ">
<subfield code="u">https://koha-test.pinoysystemslibrarian.info/cgi-bin/koha/opac-retrieve-file.pl?id=1362f36c9e3198f7ed369692140c4746</subfield>
</datafield>
....
And the following xslt:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE stylesheet>
<xsl:stylesheet version="1.0"
xmlns:marc="http://www.loc.gov/MARC21/slim"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings"
exclude-result-prefixes="marc str">
<xsl:import href="MARC21slimUtils.xsl"/>
<xsl:output method = "html" indent="yes" omit-xml-declaration = "yes" encoding="UTF-8"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="marc:record">
.... [Ommitted]
<xsl:choose>
<xsl:when test="$OPACEnableEbookReader='1'">
<xsl:attribute name="href">/ebookreader/?d=<xsl:value-of select="str:encode-uri(marc:subfield[#code='u'], true())"/>&ref=<xsl:value-of select="translate('$OPACBaseURL', '%2F', '/')"/>/cgi-bin/koha/opac-detail.pl?biblionumber=<xsl:value-of select="$biblionumber"/></xsl:attribute>
</xsl:when>
<xsl:otherwise>
What I wanted to do is that my xslt should convert HTML special characters like "/" and ":". I've tried translate to convert "%2F" which should be "/", which is in this line in my code:
<xsl:value-of select="translate('$OPACBaseURL', '%2F', '/')"/>
However, this is not being translated or converted. How do I go about this even though my output method is "html"? The OPACBaseURL is a variable which is a URL like so: https://example.com.
TIA!
This is very confusing.
If you have a string that contains %2F and you want to convert it to /, you need to use the str:decode-uri() function, not the translate() function - for example:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:variable name="myVar">abc%2Fdef</xsl:variable>
<xsl:template match="/">
<result>
<xsl:value-of select="str:decode-uri($myVar)"/>
</result>
</xsl:template>
</xsl:stylesheet>
returns:
<?xml version="1.0" encoding="UTF-8"?>
<result>abc/def</result>
Note also that the reference to the variable is not quoted.

how to find the highest value using xsl

i would like to find the highest temperate of the month APRIL, the xml has other month too.
how can i code in my xsl to retrieve the highest temperate?
here is my XML code
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="THISISA3.xsl"?>
<forecast qTime="28/10/20 10:00 PM" qLocation="Singapore">
<weather yyyymmdd="20200430">
<year>2020</year>
<month>04</month>
<date>30</date>
<comment>Plenty of sunshine</comment>
<code>sunny</code>
<highest>32.6</highest>
<lowest>28.4</lowest>
</weather>
<weather yyyymmdd="20200421">
<year>2020</year>
<month>04</month>
<date>21</date>
<comment>Plenty of sunshine</comment>
<code>sunny</code>
<highest>32.2</highest>
<lowest>29.8</lowest>
</weather>
</forecast>
It is good to provide the required output and also to show the efforts made to get the result as the community here to help with specific problems and not to write the whole code.
However, if you're newbie to start with xslt then below code with comments could help you to get started and to understand the use of stuff in xslt.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- key is used to identify nodes within an expression -->
<xsl:key name="highTemp" match="highest" use="."/>
<!-- identity template to result the transformation in source XML doc itself -->
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- matching a root node -->
<xsl:template match="forecast">
<!-- iterating through each 'weather' element -->
<xsl:for-each select="weather">
<!-- selecting node which matches the variable having required highest temperature -->
<xsl:apply-templates select=".[highest=$monthApril]"/>
</xsl:for-each>
</xsl:template>
<xsl:variable name="monthApril">
<!-- iterate only 'weather' elements which are from month of April -->
<xsl:for-each select="//weather[substring(#yyyymmdd,5,2) = '04']">
<!-- sorting in descending order so that node having highest temp comes first -->
<xsl:sort select="key('highTemp', highest)" order="descending"/>
<xsl:if test="position()=1">
<xsl:value-of select="highest"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
</xsl:stylesheet>
It would be nice if you specified what the required output is and how the variables are set and which version of xslt you use.
Below is an example XSLT 1.0 template (it has name 'highestTempForMonth') with the ability to specify the required month (it can be specified in a parameter 'month' for template) and with the ability to call this template with required month in any place you want to do it.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" >
<xsl:output method="xml" indent="yes" encoding="Utf-8"/>
<xsl:variable name="requiredMonth" select="'04'"/>
<xsl:template match="/">
<HighestTemperature>
<value>
<xsl:call-template name="highestTempForMonth">
<xsl:with-param name="month" select="$requiredMonth"/>
</xsl:call-template>
</value>
</HighestTemperature>
</xsl:template>
<xsl:template name="highestTempForMonth">
<xsl:param name="month"/>
<xsl:for-each select="/forecast/weather[month = $month]/highest">
<xsl:sort select="." data-type="number" order="descending"/>
<xsl:if test="position() = 1"><xsl:value-of select="."/></xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
There is XSLT 2.0 equivalent (with a little bit simpler template part) example.
<?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="#all" version="2.0" >
<xsl:output method="xml" indent="yes" encoding="Utf-8"/>
<xsl:variable name="requiredMonth" select="'04'"/>
<xsl:template match="/">
<HighestTemperature>
<value>
<xsl:call-template name="highestTempForMonth">
<xsl:with-param name="month" select="$requiredMonth"/>
</xsl:call-template>
</value>
</HighestTemperature>
</xsl:template>
<xsl:template name="highestTempForMonth">
<xsl:param name="month"/>
<xsl:value-of select="max(/forecast/weather[month = $month]/highest/xs:double(.))"/>
</xsl:template>
</xsl:stylesheet>
For both examples if there are no values for the specified month, the 'value' tag with an empty value will be specified. This value can be changed by a simple condition if necessary.

I have a problems with xpath, i need href link and other <a> attributes

I need get some part of a tag. My XML is like that
<div class="item">
<h2>Vyzivovy poradca</h2>
...
...
<div class="watch"><span>sometihink</span></div>
</div>
And I need href attribute and "data-id" attribute. My template look like
<xsl:variable name="url" select="xhtml:h2/xhtml:a/href"/>
<xsl:variable name="job_id" select="xhtml:div[#class = 'watch']/xhtml:a/data-id"/>
<job>
<xsl:attribute name="id"><xsl:value-of select="$job_id"/></xsl:attribute>
<url name="url"><xsl:value-of select="$url"/></url>
</job>
and template for tag a is:
<xsl:template match="xhtml:a">
<xsl:copy>
<!-- can not copy href, cause it is not absolute url ! -->
<xsl:copy-of select="#align|#title|#rel|#itemprop|#itemtype|#itemscope"/>
<xsl:attribute name="target">_blank</xsl:attribute>
<xsl:apply-templates select="*|text()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()"><xsl:value-of select="normalize-space(.)"/></xsl:template>
<xsl:template match="text()[ancestor::xhtml:pre]"><xsl:value-of select="etl:regex-replace(., '(\s|\n)+', '$1', 'g')"/></xsl:template>
but it doesn't work, some ideas?
This input XML:
<div class="item">
<h2>
Vyzivovy poradca
</h2>
...
...
<div class="watch">
<a href="sth"
data-id="292931"
data-active="somethink"
data-inactive="blablalba"
data-class="monitored"
class="watchItem"
title="watching"><span>sometihink</span></a>
</div>
</div>
Given to this XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="//a[descendant::text() = 'sometihink']">
<root>
<href>
<xsl:value-of select="#href"/>
</href>
<data-id>
<xsl:value-of select="#data-id"/>
</data-id>
</root>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
Produces this output XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<href>sth</href>
<data-id>292931</data-id>
</root>
Notes:
I'm assuming that the "sometihink" content is the most unique
characteristic of the a you seek. If it's something else (such as the parent div[#class="watch"]), let me know and we can adjust.
Update per OP's comment below:
This updated XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<root>
<item-href>
<xsl:value-of select="//div[#class='item']/h2/a/#href"/>
</item-href>
<watch-data-id>
<xsl:value-of select="//div[#class='watch']/a/#data-id"/>
</watch-data-id>
</root>
</xsl:template>
</xsl:stylesheet>
Given the above input XML will yield this output XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item-href>url.html</item-href>
<watch-data-id>292931</watch-data-id>
</root>
containing the requested attribute values.

XSL Repeating Same XML Element/Node, Not Working Correctly

So this is what my XML looks like. It's pretty darn simple, just want to lay out a bunch of links to other XML files with different names/titles for each link of course:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="index.xsl"?>
<playToc>
<play>a_and_c.xml</play>
<play>all_well.xml</play>
<play>as_you.xml</play>
<play>com_err.xml</play>
<play>coriolan.xml</play>
<play>cymbelin.xml</play>
<name>Title 1</name>
<name>Title 2</name>
<name>Title 3</name>
<name>Title 4</name>
<name>Title 5</name>
<name>Title 6</name>
</playToc>
Pretty simple, right? And so here is my 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="playToc">
<html>
<body style="text-align:center;">
<xsl:apply-templates select="play"></xsl:apply-templates>
</body>
</html>
</xsl:template>
<xsl:template match="play">
<xsl:variable name="URL">
<xsl:value-of select="."/>
</xsl:variable>
<xsl:variable name="TITLE">
<xsl:value-of select="../name"/>
</xsl:variable>
<xsl:value-of select="$TITLE"/>
<br />
</xsl:template>
</xsl:stylesheet>
And this is the output:
Title 1
Title 1
Title 1
Title 1
Title 1
Title 1
When I want this to be the output, of course:
Title 1
Title 2
Title 3
Title 4
Title 5
Title 6
Any help would be so great! Thanks a bunch!
Well the XML input is poorly structured but you can work around this by doing
<xsl:template match="play">
<xsl:variable name="pos" select="position()"/>
<a href="{.}">
<xsl:value-of select="../name[position() = $pos]"/>
</a>
<br/>
</xsl:template>
Make sure you keep the <xsl:apply-templates select="play"/> in the other template, otherwise the approach with position() won't work.
<xsl:variable name="TITLE">
<xsl:value-of select="../name"/>
</xsl:variable>
Your problem is here.
The string value of ../name is the string value of the first name child of the parent of the initial context (current) node.
What you actually want is to get the value of the name child that has the same position as the position of the current (play) node.
This complete and short 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="play">
<xsl:variable name="vPos" select="position()"/>
<a href="{.}">
<xsl:value-of select="../name[$vPos]"/>
</a><br />
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
when applied on the provided source XML document:
<playToc>
<play>a_and_c.xml</play>
<play>all_well.xml</play>
<play>as_you.xml</play>
<play>com_err.xml</play>
<play>coriolan.xml</play>
<play>cymbelin.xml</play>
<name>Title 1</name>
<name>Title 2</name>
<name>Title 3</name>
<name>Title 4</name>
<name>Title 5</name>
<name>Title 6</name>
</playToc>
produces the wanted, correct result:
Title 1
<br/>
Title 2
<br/>
Title 3
<br/>
Title 4
<br/>
Title 5
<br/>
Title 6
<br/>
Do note:
There is no need to use xsl:apply-templates at all.
There is just one template.

Need to validate html styles

i am converting docx file into html using xslt. My resulting html contains styles like margin-top:NaN pt;, the style value NaN is ignored in browser by default.But i have to validate for the presence of such attributes and have to remove before viewing in browser...
Please help me...Thanks in advance...
Have you tried W3C CSS validator?
http://jigsaw.w3.org/css-validator/
You can use it programatically thanks to a SOAP Web service:
http://jigsaw.w3.org/css-validator/api.html
You should check for 'NaN' before adding inline styles.
E.g. consider this XML:
<?xml version="1.0"?>
<t>
<Number>adsfdasf</Number>
<Number></Number>
<Number>100</Number>
<Number>1.234234</Number>
</t>
Then you can:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="Number">
<xsl:value-of select="concat(., ' : ')"/>
<xsl:if test="not(string(number()) = 'NaN')">valid</xsl:if>
<xsl:if test="string(number()) = 'NaN'">invalid</xsl:if>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
Result:
adsfdasf : invalid
: invalid
100 : valid
1.234234 : valid
It is too-late to chack for NaN in the generated result.
Producing unwanted output should be prevented!
Here is an example, that avoids generating NaN:
<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()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="num[number(.) = number(.)]">
<span style="margin-top:{.}"/>
</xsl:template>
<xsl:template match="num[not(number(.) = number(.))]"/>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<t>
<num>helo</num>
<num></num>
<num>100</num>
<num>1.234234</num>
</t>
only correct output (no NaN) is produced:
<t>
<span style="margin-top:100"/>
<span style="margin-top:1.234234"/>
</t>