Reference to undeclared namespace prefix: 'json'. while renaming xml attibute with xslt - json

Updated with Minimal, Complete and Verifiable information thanks #Kenneth for drawing my attention.
So, I'm trying to rename an xml attribute using xslt, but I keep getting this error message:
Reference to undeclared namespace prefix: 'json'.
This is my source xml:
<?xml version="1.0" encoding="utf-8"?>
<data>
<code>SO000009</code>
<businessPartner>70833A356B9A428CBDDCD2A76A49681F</businessPartner>
<startDateTime>2018-01-25T15:24:27Z</startDateTime>
<subject>Test</subject>
<equipments jsonArray="true">80202</equipments>
</data>
This is how I want the xml to be:
<?xml version="1.0" encoding="utf-16"?>
<data xmlns:json="http://james.newtonking.com/projects/json">
<code>SO000009</code>
<businessPartner>70833A356B9A428CBDDCD2A76A49681F</businessPartner>
<startDateTime>2018-01-25T15:24:27Z</startDateTime>
<subject>Test</subject>
<equipments json:Array="true">80202</equipments>
</data>
And this is my xslt:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="/data">
<data xmlns:json="http://james.newtonking.com/projects/json">
<xsl:apply-templates select="node()|#*" />
</data>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<xsl:template match="#jsonArray">
<xsl:attribute name="json:Array">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
When I'm trying to convert my xml, I keep getting this message:
Error occurred while compiling stylesheet 'CS_jsonArray.xslt'.
Code: 0x80004005
Reference to undeclared namespace prefix: 'json'.

After looking in the 'Related' sidebar, I did found the answer to my own question.
XSL transformation - Namespace prefix undeclared
So for those who have a same issue, be sure the namespace you want to change the attribute names for, is also in the xslt tag itself...
This is how my xslt started:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>...
This is how I changed it:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:json="http://james.newtonking.com/projects/json">
<xsl:output indent="yes"/>...

Related

Convert text to uppercase between tag keeping them

I'm trying to convert HTML content to uppercase using XSLT, but the requirement is to keep the tag hierarchy unaltered (i.e., just change the text).
For example: <p>some text <b>other text</b></p>
should result in
<p>SOME TEXT <b>OTHER TEXT</b></p>.
With the following XSLT I managed to convert the text to uppercase, but the result loses the tag hierarchy.
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output encoding="UTF-8" indent="no" method="xhtml" standalone="0" version="1.0"/>
<xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:template match="/">
<xsl:value-of select="translate(/, $smallcase, $uppercase)"/>
</xsl:template>
</xsl:transform>
Is there any way to keep the tags unaltered?
Thanks in advance.
Try:
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:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select="translate(., $smallcase, $uppercase)"/>
</xsl:template>
</xsl:stylesheet>
Note that xhtml is not a valid output method in XSLT 1.0.

Convert Embedded JSON to XML using XSLT

When transforming an XML document with XSLT, is it possible to convert embedded JSON (i.e. JSON formatted content) in the process?
For example the following: -
<form>
<data>[{"id":1,"name":"Hello"},{"id":2,"name":"World"}]</data>
</form>
Would be converted to: -
<form>
<data>
<id name="Hello">1</id>
<id name="World">2</id>
</data>
</form>
Parsing JSON is supported in XSLT 3.0 so using the commercial versions of Saxon 9.7 you could use
<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:strip-space elements="*"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="data">
<xsl:copy>
<xsl:apply-templates select="parse-json(.)?*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=".[. instance of map(xs:string, item())]">
<id name="{.?name}">
<xsl:value-of select=".?id"/>
</id>
</xsl:template>
</xsl:stylesheet>
Using the open source version of Saxon 9.7 (i.e. Saxon 9.7 HE) the following takes up the suggestion made by wero to use json-to-xml and shows how to implement the requirement:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math fn"
version="3.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="data">
<xsl:copy>
<xsl:apply-templates select="json-to-xml(.)//fn:map"/>
</xsl:copy>
</xsl:template>
<xsl:template match="fn:map">
<id name="{fn:string[#key = 'name']}">
<xsl:value-of select="fn:number[#key = 'id']"/>
</id>
</xsl:template>
</xsl:stylesheet>
Saxon 9.7 HE is available on Maven and from http://saxon.sourceforge.net/
It should be possible in XSLT 3.0, given that it has a json-to-xml function:
Parses a string supplied in the form of a JSON text, returning the
results in the form of an XML document node.
You could try to get this to run with the current implementation in Saxon.

Time format in XSLT 2.0

I worked with xslt 2.0 and Java( Saxon-HE ).Saxon-HE do not support xslt date-time format.I have current-date() and current-time() functions and I need them in the following format time(17:31), date(03/06).Please help me and give any suggestion hot to do it.Thanks a lot of
Please try the below tranformation:
<?xml version='1.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"/>
<xsl:template match="test">
<xsl:variable name="currenttime" select="current-dateTime()" as="xs:dateTime"/>
<xsl:value-of select="format-dateTime($currenttime,'[H]')"/><xsl:text>:</xsl:text><xsl:value-of select="format-dateTime($currenttime,'[m]')"/>
<xsl:text>
</xsl:text>
<xsl:value-of select="format-dateTime($currenttime,'[M]')"/><xsl:text>/</xsl:text><xsl:value-of select="format-dateTime($currenttime,'[D]')"/>
</xsl:template>
</xsl:stylesheet>

xml tags passed as arguments to xsl

How to modify the below xsl to process parameters whose value is tags. Instead of using w:p and w:pPr/w:pStyle/#w:val i will be passing them as args
Actual XSl:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml"
>
<xsl:param name="styleName"/>
<xsl:output method="text"/>
<xsl:template match="w:p"/>
<xsl:template match="w:p[w:pPr/w:pStyle/#w:val[matches(., concat('^(',$styleName,')$'),'i')]]">
<xsl:value-of select="."/><xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
Required XSL:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml">
<xsl:param name="styleName" select="'articletitle'"/>
<xsl:param name="para" select="'//w:p[w:pPr/w:pStyle/#w:val[matches(.,concat('^(',$styleName,')$')]]'"/>
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:for-each select="$para">
<xsl:value-of select="."/><xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
NOTE: You should get used to give information about which version of xslt and which processor you are using. In this case, the answer is valid only if you are using XSLT 2.0
This is not a complete answer, but you can start by looking at this approach:
Try using local-name and in-scope-prefixes (only available in XSLT 2.0) to match a node dynamically.
Here you have an example template to replace your empty template:
<xsl:template match="*[local-name()=substring-after($para,':') and in-scope-prefixes(.)[.=substring-before($para,':')]]"/>
For the second part of the expression ($parastyle), I can only think about writing your own function to evaluate it dynamically.
I'll try to post an example of such a function later on.
I fugured out the problem in my coding, is in second line,
<xsl:param name="para" select="'//w:p[w:pPr/w:pStyle/#w:val[matches(.,concat('^(',$styleName,')$')]]'"/>
Since i have given the quotes in select attribute the value has been considered as string instead of xpath expression.

How have xsl:function return a string value including html tags

I am attempting to transpose a java function to an xsl:function spec.
The function basically places html tags around substrings.
I now bump into difficulties: using the java inline code this works perfectly, but I am unable to figure out how to prevent output escaping when using the xsl:function.
How can I achieve the output to contain the wanted html tags?
A simplified example of what I am trying to achieve is the following:
input parameter value "AB" should lead to a string A<b>B</b>, shown in html browser as AB of course.
Example function I tried is the below; but then the resulting string is A&lt ;b&gt ;B&lt ;/b&gt ; (note that I had to add blanks to prevent the entities from getting interpreted in this editor), which of course shows up in browers as A<b>B</b>.
Note that xsl:element cannot be used in the xsl:function code, because that has no effect; I want the string result of the function call to contain < and > characters, and then add the string result to the output result file.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:custom="http://localhost:8080/customFunctions">
<xsl:output method="html" version="4.0" encoding="UTF-8" indent="yes"/>
<xsl:function name="custom:test">
<xsl:param name="str"/>
<xsl:value-of select="substring($str,1,1)"/>
<xsl:text disable-output-escaping="yes"><![CDATA[<b>]]></xsl:text>
<xsl:value-of select="substring($str,2)"/>
<xsl:text disable-output-escaping="yes"><![CDATA[</b>]]></xsl:text>
</xsl:function>
<xsl:template match="/">
<xsl:element name="html">
<xsl:element name="body">
<xsl:value-of select="custom:test('AB')"/>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Here is an example, use sequence instead value-of and make sure your function returns nodes (which is usually simply done by writing literal result elements):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:custom="http://localhost:8080/customFunctions"
exclude-result-prefixes="custom">
<xsl:output method="html" version="4.0" encoding="UTF-8" indent="yes"/>
<xsl:function name="custom:test">
<xsl:param name="str"/>
<xsl:value-of select="substring($str,1,1)"/>
<b>
<xsl:value-of select="substring($str,2)"/>
</b>
</xsl:function>
<xsl:template match="/">
<xsl:element name="html">
<xsl:element name="body">
<xsl:sequence select="custom:test('AB')"/>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>