xslt: get attribute from xsl itself - xslt

is it possible to read an xsl attribute from the xsl document itself? I need something like this:
mystyle.xsl
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.w3.org/1999/xhtml"
id="I'm a special stylesheet">
...
<!-- Output should be: "stylesheet id: I'm a special stylesheet" -->
<xsl:text>stylesheet id:</xsl:text><xsl:value-of select="/#id"/>
...
</xsl:stylesheet>
Is that possible?

Yes, you can use <xsl:value-of select="document('')/xsl:stylesheet/#id"/>, at least as long as the stylesheet has been loaded from a URI.

Related

How to add cxml doctype using XSLT

I am generating correct cxml but doctype is missing in the beginning.
How can I add the below doc type after <?xml version="1.0" encoding="utf-8"?> and copy the remaining xml using XSLT mapping.
<!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.032/cXML.dtd">
Desired output should be like
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.032/cXML.dtd">
<xml>
<field>.... (followed by remaining xml structure)
Thanks,
Varun
Try
<xsl:output method="xml"
doctype-system="http://xml.cxml.org/schemas/cXML/1.2.032/cXML.dtd"
/>

Passing and parsing XML as a parameter to XSLT 2.0

I'm trying to figure out how to pass XML into a XSLT document and parse it as you would on any node.
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:param name="xmlparam"></xsl:param>
<xsl:template match="/">
<xsl:value-of select="node()"></xsl:value-of>
<xsl:value-of select="$xmlparam/coll"></xsl:value-of>
</xsl:template>
</xsl:stylesheet>
xmlparam:
<?xml version="1.0" encoding="UTF-8"?>
<coll>
<title>Test</title>
<text>Some text</text>
</coll>
Input:
<?xml version="1.0" encoding="UTF-8"?>
<coll>
Root doc
</coll>
Output:
<?xml version="1.0" encoding="UTF-8"?>
Root doc
XPTY0019: Required item type of first operand of '/' is node(); supplied value has item type xs:untypedAtomic
Does anyone know how to parse XML passed in as a parameter to XSLT? Due to certain restraints, I cannot read in a file, it needs to be a parameter.
You could get your XML input to be parsed by the style sheet by using the document function, e.g. like (from memory, so maybe not completely accurate)
<xsl:variable name="myData" select="document('myData')"/>
AND registering a custom URIResolver with the with your Transformer. This custom URIResolver will get "myData" as value of the parameter href of its resolve method and could then obtain the content of the document from e.g. a String. This would give you roughly the same flexibility as adding the content as a parameter.
Code sketch (assuming the obvious implementation of MyURIResolver):
Transformer myTransformer = getMyTransformer();
String myXmlDocument = getMyXmlDocumetAsString();
URIResolver myURIResolver = new MyURIResolver();
myURIResolver.put("myData", myXmlDocument);
myTransformer.setURIResolver(myURIResolver);
myTransformer.transform(source, result);

xslt parse XML string into variable and use Xpath

My (simplified) input XML file contains the following:
<?xml version="1.0" encoding="UTF-8"?>
<main>
<DATA_RECORD>
<MESSAGE><pd>
<cdhead version="13"/>
</pd></MESSAGE>
</DATA_RECORD>
</main>
The MESSAGE element value is a character-escaped XML instance. It represents the following XML:
<pd>
<cdhead version="13"/>
</pd>
I would like to apply an xsl transformation on the input XML and somehow parse the MESSAGE contents into a variable and use Xpath expressions to access its details.
I tried adding a javascript function as below, but the object returned by the script apparently is of an incorrect DOM subclass (see result underneath). For completeness, I added an extra function that returns the DOM contents as a string.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ms="urn:schemas-microsoft-com:xslt"
xmlns:my="http://example.com/my"
exclude-result-prefixes="ms my">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<ms:script language="JScript" implements-prefix="my">
<![CDATA[
function parseToDOM (input) {
var doc = new ActiveXObject('Msxml2.DOMDocument.6.0');
doc.loadXML (input);
return doc.documentElement;
};
function parseToXMLString (input) {
var doc = new ActiveXObject('Msxml2.DOMDocument.6.0');
doc.loadXML (input);
return doc.documentElement.xml;
};
]]>
</ms:script>
<xsl:template match="/">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="DATA_RECORD">
<xsl:variable name="DOM"><xsl:copy-of select="my:parseToDOM (MESSAGE)"/></xsl:variable>
<xsl:variable name="XML"><xsl:copy-of select="my:parseToXMLString (MESSAGE)"/></xsl:variable>
<msg1><xsl:value-of select="$XML"/></msg1>
<msg2><xsl:value-of select="$XML" disable-output-escaping="yes"/></msg2>
<dom><xsl:copy-of select="$DOM"/></dom>
<version><xsl:value-of select="$DOM/pd/cdhead/#version"/></version>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
Result:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<msg1><pd>
<cdhead version="13"/>
</pd></msg1>
<msg2><pd>
<cdhead version="13"/>
</pd></msg2>
<dom/>
<version></version>
</root>
How can I make the Jscript function return a result that allows the use of Xpath?
By the way, is there some XSLT 1.0 function available that allows parsing the escaped XML string to a result that allows the use of Xpath?
ADDITION
I have been trying some variations and got closer to a solution. First, Altova XMLSpy allows choosing the xsl processor, and the above resulted when using the built-in one. Of course I need MSXML 6.0 and when choosing that one, errors occurred as I had to parse input.text instead. But I only succeeded in being able to use Xpath expressions in the result after doing extra stuff in the javascript. It transpired that while < and the like are parsed into < etcetera, this is not enough to arrive at the proper DOM result. So I resorted to unescaping the input string first.
But I hit another snag: where the below works fine, it does not when I use input.text instead of the literal below.
See below the xslt.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ms="urn:schemas-microsoft-com:xslt"
xmlns:my="http://example.com/my"
exclude-result-prefixes="ms my">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<ms:script language="JScript" implements-prefix="my">
<![CDATA[
function parseToDOM (input) {
var doc = new ActiveXObject('Msxml2.DOMDocument.6.0');
doc.loadXML (unescapeXML ('<pd>
<cdhead version="13"/>
</pd>'));
//doc.loadXML (unescapeXML (input.text));
return doc;
};
function unescapeXML (str) {
var ostr = str;
ostr = ostr.replace (/"/g, '"');
ostr = ostr.replace (/</g, '<');
ostr = ostr.replace (/=/g, '=');
ostr = ostr.replace (/>/g, '>');
return ostr;
};
]]>
</ms:script>
<xsl:template match="/">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="DATA_RECORD">
<xsl:variable name="msg" select="my:parseToDOM (MESSAGE)"/>
<tst><xsl:value-of select="$msg/pd/cdhead/#version"/></tst>
</xsl:template>
</xsl:stylesheet>
Now results in
<?xml version="1.0" encoding="UTF-8"?>
<root>
<tst>13</tst>
</root>
Which is exactly what I want.
But as remarked above, when I comment the parsing of the literal and use the input instead, like so:
//doc.loadXML (unescapeXML ('<pd>
<cdhead version="13"/>
</pd>'));
doc.loadXML (unescapeXML (input.text));
I get the following error (in Altova XML Spy with MSXML 6.0 as xslt parser):
XSL transformation failed due to following error:
Microsoft JScript runtime error
'undefined' is null or not an object
line = 10, col = 3 (line is offset from the start of the script block).
Error returned from property or method call.
Which points at the first javascript replace statement.
And also, IE9 cannot process the following properly:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test.xslt"?>
<main>
<DATA_RECORD>
<MESSAGE><pd>
<cdhead version="13"/>
</pd></MESSAGE>
</DATA_RECORD>
</main>
When I open this file in IE9 (where test.xslt is the version of the transformation where the input is ignored and instead a literal is processed, hence the one that is OK in XML Spy), I get a processing error:
XML5001: Applying Integrated XSLT Handling.
XSLT8690: XSLT processing failed.
Why is all this and how can I correct it?
Starting from the ADDITION above, I reached a solution by finetuning it a little.
To avoid having to do input.text and use plain input instead, the xsl has to contain a conversion of the element to a string by applying the xslt string function (I thought it was a string already, but apparently that is not the case). In addition, it was not necessary any more to apply the replace statements now.
Thus
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ms="urn:schemas-microsoft-com:xslt"
xmlns:my="http://example.com/my"
exclude-result-prefixes="ms my">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<ms:script language="JScript" implements-prefix="my">
<![CDATA[
function parseToDOM (input) {
var doc = new ActiveXObject('Msxml2.DOMDocument.6.0');
doc.loadXML (input);
return doc;
};
]]>
</ms:script>
<xsl:template match="/">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="DATA_RECORD">
<xsl:variable name="msg" select="my:parseToDOM (string(MESSAGE))"/>
<tst><xsl:value-of select="$msg/pd/cdhead/#version"/></tst>
</xsl:template>
</xsl:stylesheet>
works: when applied on
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test.xslt"?>
<main>
<DATA_RECORD>
<MESSAGE><pd>
<cdhead version="13"/>
</pd></MESSAGE>
</DATA_RECORD>
</main>
the result is
<?xml version="1.0" encoding="UTF-8"?>
<root>
<tst>13</tst>
</root>
Unluckily, IE9 still fails in loading the XML with referred XSLT; and I discovered why.
I had to tick the box in Internet Options/Advanced/Security/Allow active content to run in files on My Computer - and also restart IE - this makes IE9 process the file correctly. Of course, the result not being html means that the result can only be viewed in F12/Script tab, but this was just an example and I will incorporate it in an xslt that generates proper html.

XSLT - using hardcoded values and looping on them

I'm very new to xslt and trying to learn. The focus to transform my data xml and bind the output xml to the adobe form.
I have a xml of the following structure.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<envelope xmlns="http://www.mydata.de/xem/reporting/datafile">
<sources>
<source>
<data>
<REPORT>
<EM_ESOURCE>
<EM_ES_MEASURE>
<ID>1037343</ID>
<ES_ID>1006222</ES_ID>
<ES_NAME>MFC-D-002</ES_NAME>
<EM_MAT_NAME>Cyprinella leedsi</EM_MAT_NAME>
<START_DATE>1/19/98</START_DATE>
<LABORATORY>Thornton</LABORATORY>
<LC50>>100%</LC50>
<TESTTYPE/>
<IC25/>
</EM_ES_MEASURE>
<EM_ES_MEASURE>
<ID>1037344</ID>
<ES_ID>1006222</ES_ID>
<ES_NAME>MFC-D-002</ES_NAME>
<EM_MAT_NAME>C Dubia</EM_MAT_NAME>
<START_DATE>3/2/98</START_DATE>
<LABORATORY>Thornton</LABORATORY>
<LC50>>120%</LC50>
<TESTTYPE>Routine</TESTTYPE>
<IC25/>
</EM_ES_MEASURE>
</EM_ESOURCE>
</REPORT>
</data>
</source>
</sources>
This is the result of one of the queries. The Adobe report requires the materials to be shown always in a particular order regardless of what the query returns. So I decided to hardcode the order of materials in the xsl internally, loop on this list and then fetch corresponding "LC50" values from the data xml.
Following is the xsl that I started:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:rep="http://www.technidata.de/xem/reporting/datafile"
xmlns:s="http:/materials.data"
xmlns:java="http://xml.apache.org/xslt/java">
<xsl:output method="html" omit-xml-declaration="yes" encoding="UTF-8"/>
<!-- Suppress copy of restrictions -->
<!--xsl:template match="text()|#*"/-->
<xsl:key name="material-lookup" match="s:material" use="s:name"/>
<xsl:template match="/">
<REPORT>
<HEADERS>
<STARTDATE><xsl:value-of select="substring(/rep:envelope/rep:sources/rep:restrictions/rep:START_DATE,1,10)"/></STARTDATE>
<ENDDATE><xsl:value-of select="substring(/rep:envelope/rep:sources/rep:restrictions/rep:START_DATE,16,24)"/></ENDDATE>
<FACILITY><xsl:value-of select="normalize-space(/rep:envelope/rep:sources/rep:restrictions/rep:ID_ATTRIBUTE_ID_NAME)"/></FACILITY>
</HEADERS>
<MATERIALS>
</MATERIALS>
</REPORT></xsl:template>
<s:materials>
<s:material>
<s:name>Cyprinella leedsi</s:name>
<s:parameter>LC(ROUTINE) </s:parameter>
</s:material>
<s:material>
<s:name>C Dubia</s:name>
<s:parameter>LC50(ROUTINE) </s:parameter>
</s:material>
</s:materials>
</xsl:stylesheet>
I'm not sure how to fill in the the MATERIALS node with the materials in the order defined in the xslt and their corresponding LC50 values from the data xml.
Use the document('') function to XPath into the XSLT file itself.

xml namespaces in xsl transform - ignore blank?

I'm new to xsl and am trying to write a template to transform xml to html.
I have an xml document that begins
<?xml version="1.0" encoding="UTF-8"?>
<data xmlns:autn="http://schemas.com/aci/"
xmlns="http://iptc.org/std/nar/2006-10-01/">
<name>Bob</name>
and my xsl template begins
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:autn="http://schemas.autonomy.com/aci/">
<xsl:output method="html" omit-xml-declaration="yes"/>
<xsl:template match="/">
...
<body>
<p>user name:</p>
<p><xsl:value-of select="data/name"/></p>
The problem is, if I do
I don't get anything back for the value-of select.
If I do
I get 'Bob' but I lose all my html.
What am I missing?
You are missing the default namespace of the XML document:
xmlns="http://iptc.org/std/nar/2006-10-01/"
Add it to the XSLT as well:
<xsl:stylesheet version="1.0"
xmlns:mynamespace="http://iptc.org/std/nar/2006-10-01/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:autn="http://schemas.autonomy.com/aci/">
And use that namespace in the xsl:value-of:
<xsl:value-of select="mynamespace:data/mynamespace:name" />