So I have an XML file validated by its DTD and now I have to make transformations with an XSLT that should output all the each user's page to an XHTML file. I was told that I should use a 'for-each' but well, how can I do so that I get as an output one file for each user? (each output file should be an XHTML file with the information a user, in total one file per user)
XML (sample):
<store>
<users>
<user id="user1">
<name username="user1">User 1</name>
<email>user1#email.com</email>
<birth birth_date=""></birth>
<mob_number>123</mob_number>
<address>Street1</address>
<picture></picture>
<basket></basket>
</user>
<user id="user2">
<name username="user2">User 2</name>
<email>user2#email.com</email>
<birth birth_date=""></birth>
<mob_number>123</mob_number>
<address>Street1</address>
<picture></picture>
<basket></basket>
</user>
<user id="user3">
<name username="user3">User 3</name>
<email>user3#email.com</email>
<birth birth_date=""></birth>
<mob_number>123</mob_number>
<address>Street1</address>
<picture></picture>
<basket></basket>
</user>
<user id="user4">
<name username="user4">User 4</name>
<email>user4#email.com</email>
<birth birth_date=""></birth>
<mob_number>123</mob_number>
<address>Street1</address>
<picture></picture>
<basket></basket>
</user>
</users>
</store>
Thank you
As #MartinHonnen noted, xsl:result-document is the way to go.
This answer outputs each user as a separate file named HTML_userX:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:strip-space elements="*" />
<xsl:template match="/store/users">
<xsl:for-each select="user">
<xsl:result-document href="{concat('HTML_',#id)}" method="xhtml">
<xsl:copy-of select="." />
</xsl:result-document>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Related
I need to transform a json message to XML. I have created a basic XSL transform script but the resulting XML uses 'map' tags with the json values as 'key' attributes.
Is there a way to have the name values used as tags or do I have to write a second transform XSL to get what I want?
json:
<?xml version="1.0"?>
<data>
{ "Policies":
{
"Policy": {
"PolicyNum": "1234",
"Customer": "Smith"
},
"Policy": {
"PolicyNum": "5678",
"Customer": "Jones"
}
}
}
</data>
xsl:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:math="http://www.w3.org/2005/xpath-functions/math" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs math" version="3.0">
<xsl:output indent="yes" omit-xml-declaration="no" />
<xsl:template match="data">
<xsl:copy-of select="json-to-xml(.)"/>
</xsl:template>
</xsl:stylesheet>
resulting XML: (using https://xslttest.appspot.com/)
<?xml version="1.0" encoding="UTF-8"?>
<map xmlns="http://www.w3.org/2005/xpath-functions">
<map key="Policies">
<map key="Policy">
<string key="PolicyNum">1234</string>
<string key="Customer">Smith</string>
</map>
<map key="Policy">
<string key="PolicyNum">5678</string>
<string key="Customer">Jones</string>
</map>
</map>
</map>
The XML I need:
<Policies>
<Policy>
<PolicyNum>1234</PolicyNum>
<Customer>Smith</Customer>
</Policy>
<Policy>
<PolicyNum>5678</PolicyNum>
<Customer>Jones</Customer>
</Policy>
</Policies>
Instead of copying the XML map, push it through templates and transform that map into elements using the #key for the name:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
exclude-result-prefixes="xs math" version="3.0">
<xsl:output indent="yes" omit-xml-declaration="no" />
<xsl:template match="data">
<xsl:apply-templates select="json-to-xml(.)"/>
</xsl:template>
<xsl:template match="fn:*[#key]">
<xsl:element name="{#key}">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
<xsl:template match="fn:map">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
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.
I want to convert JSON to XML using XSLT. But not able to achieve the expected output.
Below is the JSON request:
{
"Store": [
{
"Book": "Cartoons",
"ID": "ABC"
}
]
}
The XSLT which I tried:
<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"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
xmlns:emp="http://www.semanticalllc.com/ns/employees#"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:j="http://www.w3.org/2005/xpath-functions"
exclude-result-prefixes="xs math xd h emp"
version="3.0"
expand-text="yes">
<xsl:template match="/">
<xsl:copy>
<xsl:apply-templates select="json-to-xml(.)/*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[#key]" xpath-default-namespace="http://www.w3.org/2005/xpath-functions">
<xsl:element name="{#key}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
But I'm getting empty Response.
You need to pass the JSON as a parameter or read it from a file, the input to your XSLT is either XML or you can start with a named template:
<?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="3.0">
<xsl:param name="json" as="xs:string" expand-text="no">{
"Store": [
{
"Book": "Cartoons",
"ID": "ABC"
}
]
}</xsl:param>
<xsl:output indent="yes"/>
<xsl:template match="/" name="xsl:initial-template">
<xsl:sequence select="json-to-xml($json)"/>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/93wniTJ
The result of the function for your sample is
<map xmlns="http://www.w3.org/2005/xpath-functions">
<array key="Store">
<map>
<string key="Book">Cartoons</string>
<string key="ID">ABC</string>
</map>
</array>
</map>
but of course you can run it through further templates to transform it to a different format.
The pattern match="/" matches a document node (the root of an XML tree). It won't match your input if the input is JSON.
XSLT 3.0 isn't actually that good at processing JSON using template rules: it can be done, but it isn't very convenient. It's usually more convenient to use functions. You can supply the JSON input as the value of an xsl:param and process it in code from your xsl:initial-template; or if you're feeling more ambitious you could actually initiate the XSLT processing by invoking a public xsl:function that takes the JSON input as a parameter.
The traditional match="/" entry to a stylesheet only works for the traditional use of XSLT to process an XML input document.
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>
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