XSLT convert HTML special characters despite output method is html - 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.

Related

Output multiple elements as a JSON array in XSLT

I have an XSL Code as shown below.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" />
<xsl:variable name="inlineAddressArray">
<addrline>Home1</addrline>
<addrline>Home2</addrline>
<addrline>Home3</addrline>
</xsl:variable>
<xsl:variable xmlns:exsl="http://exslt.org/common" name="data" select="exsl:node-set($inlineAddreddArray)" />
<addressLines>
<xsl:value-of select="$data/addrline" />
</addressLines>
</xsl:stylesheet>
My expected JSON output should be:
"addressLines":"[Home1,Home2,Home3]"
Output that I'm getting
"addressLines": "Home1Home2Home3"
Basically it is just concatenating every element as a single element.
But, I should get three elements separately as shown above.
Can anyone please help me on this? Don't mind if it's a silly query. I'm very new to XSLT :)
No need for Newtonsoft.Json.JsonConvert.SerializeXmlNode() .
Given this xml:
<inlineAddressArray>
<addrline>Home1</addrline>
<addrline>Home2</addrline>
<addrline>Home3</addrline>
</inlineAddressArray>
Using this xslt 2.0:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="text" encoding="UTF-8" />
<xsl:template match="inlineAddressArray">
<xsl:text>"addressLines":"[</xsl:text>
<xsl:value-of select="addrline" separator=","/>
<xsl:text>]"</xsl:text>
</xsl:template>
</xsl:stylesheet>
or using xslt 1.0
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" encoding="UTF-8" />
<xsl:template match="inlineAddressArray">
<xsl:text>"addressLines":"[</xsl:text>
<xsl:apply-templates select="addrline"/>
<xsl:text>]"</xsl:text>
</xsl:template>
<xsl:template match="addrline">
<xsl:value-of select="."/>
<xsl:if test="not(position()=last())">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
results in this :
"addressLines":"[Home1,Home2,Home3]"
UPDATE
if you also want to deal with empty addrline like i.e.
<inlineAddressArray>
<addrline>Home1</addrline>
<addrline>Home2</addrline>
<addrline></addrline>
</inlineAddressArray>
Your xslt 1.0 could look like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" encoding="UTF-8" />
<xsl:template match="inlineAddressArray">
<xsl:text>"addressLines":"[</xsl:text>
<xsl:apply-templates select="addrline"/>
<xsl:text>]"</xsl:text>
</xsl:template>
<xsl:template match="addrline">
<xsl:value-of select="."/>
<xsl:if test=" following-sibling::addrline[(normalize-space(.))]">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:template>
<xsl:template match="addrline[not(normalize-space(.))]"/>
</xsl:stylesheet>

How to select a node from an xml created by json-to-xml()

I am trying to get an element from a JSON after converting it to XML.
Working example: https://xsltfiddle.liberty-development.net/gWmuiJf/1
In this example, it is parsed successfully but when I want to select a node with the code below I could not bring the data I need.
<xsl:copy-of select="json-to-xml(root)//map[#key='identifier']"/>
JSON:
<root><![CDATA[{
"identifier": {
"use": "<div xmlns=\"http://www.w3.org/1999/xhtml\"> </div>"
}
}]]></root>
XSL:
<?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="3.0">
<xsl:output indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select="json-to-xml(root)"/>
</xsl:template>
</xsl:stylesheet>
My desired output is this:
<map key="identifier">
<string key="use"><div xmlns="http://www.w3.org/1999/xhtml"> </div></string>
</map>
or this
<string key="use"><div xmlns="http://www.w3.org/1999/xhtml"> </div></string>
The XML that is being generated by json-to-xml has a default namespace
<map xmlns="http://www.w3.org/2005/xpath-functions">
<map key="identifier">
<string key="use"><div xmlns="http://www.w3.org/1999/xhtml"> </div>
</string>
</map>
</map>
Your XSLT is looking for a map in no namespace. So, you will have to adjust the xpath to cope with any namespace, but also use xsl:apply-templates so you can have a template that removes the namespace from the elements.
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="3.0">
<xsl:output indent="yes"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="/">
<xsl:apply-templates select="json-to-xml(root)//*:map[#key='identifier']"/>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>

xslt 3.0 json-to-xml and xml-to-json conversion

Currently I need to convert json to xml and xml to json vice versa using XSLT 3.0 & Saxon-HE.
Below is my json abc.xml file
<?xml version="1.0" encoding="UTF-8" ?>
<root>
<data>{
"cars" : [
{"doors" : "4","price" : "6L"},
{"doors" : "5","price" : "13L"}
]
}
</data>
</root>
Below is xsl file xyz.xsl
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:output indent="yes"/>
<xsl:template match="data">
<xsl:copy-of select="json-to-xml(.)"/>
</xsl:template>
Below is output xml
<?xml version="1.0" encoding="UTF-8"?>
<map xmlns="http://www.w3.org/2005/xpath-functions">
<array key="cars">
<map>
<string key="doors">4</string>
<string key="price">6L</string>
</map>
<map>
<string key="doors">5</string>
<string key="price">13L</string>
</map>
</array>
</map>
Now My Question is how i can get back the same json from the output.xml? I am trying this using xslt function xml-to-json() but the output format is looking incorrect. Below is the xsl and output m getting.
123.xsl
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:output indent="yes"/>
<xsl:template match="data">
<xsl:copy-of select="xml-to-json(.)"/>
</xsl:template>
</xsl:stylesheet>
Output JSon
Try this example here https://xsltfiddle.liberty-development.net/3NzcBsQ
In xsl I am selecting wrong template named data. because data template is not in output.xml. I am not sure what should i write here.
<xsl:template match="data">
You need to match on /, as in
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:value-of select="xml-to-json(.)"/>
</xsl:template>
</xsl:stylesheet>
then the result is
{"cars":[{"doors":"4","price":"6L"},{"doors":"5","price":"13L"}]}
With
<xsl:template match="/">
<xsl:value-of select="xml-to-json(., map { 'indent' : true() })"/>
</xsl:template>
you get indentation although Saxon is not doing a nice job there:
{ "cars" :
[
{ "doors" : "4",
"price" : "6L" },
{ "doors" : "5",
"price" : "13L" } ] }
https://xsltfiddle.liberty-development.net/b4GWVd/1

XML to JSON (Webhooks slack)

I would like to convert an XML to JSON using xslt transformation.The purpose is to POST into my slack channel using Incoming Webhooks.
XML File :
<?xml version="1.0" encoding="UTF-8" ?>
<Asset version="1.0">
<Process>
<Date>2017-01-24 14:47:35</Date>
<Status>Success</Status
> <Profile>TEST</Profile>
<Station>DESKTOP</Station>
<User>Système</User>
<Application>APP</Application>
</Process>
<Source>
</Source>
<Target>
<Name>Hello.mp4</Name>
</Target>
</Asset>
I tried this :
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="txt" omit-xml-declaration="yes" encoding="UTF-8"/>
<xsl:template match="/">
{
"text":"<xsl:value-of select="Asset/Process/Profile"/>",
"text":"<xsl:value-of select="Asset/Process/Date"/>",
"text":"<xsl:value-of select="Asset/Target/Name"/>",
"text":"<xsl:value-of select="Asset/Process/Status"/>",
}
</xsl:template>
</xsl:stylesheet>
But i've got this error : 500 - missing_text_or_fallback_or_attachments
Do you have any idea ?
I need to have an JSON like this :
{ "text": "Date: 2017-01-24 14:47:35\n Status: Success\n Profile: TEST\n Station: DESKTOP\n User: Système\n Application: APP"}
https://api.slack.com/incoming-webhooks#sending_messages
Here is the XSLT which produces the desired JSON String:
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="text" omit-xml-declaration="yes" encoding="UTF-8"/>
<xsl:template match="/">
<xsl:text>{ "text": "</xsl:text>
<xsl:for-each select="Asset/Process/*">
<xsl:choose>
<xsl:when test="position()=1">
<xsl:value-of select="concat(local-name(),': ',.,'\n')"/>
</xsl:when>
<xsl:when test="position()=last()">
<xsl:value-of select="concat(' ',local-name(),': ',.)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(' ',local-name(),': ',.,'\n')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:text>"}</xsl:text>
</xsl:template>
</xsl:stylesheet>

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.