How to get a value from a JavaScript in XSLT? - html

I have the following XML and XSLT to transform to HTML.
XML
<?xml version="1.0" encoding="UTF-8"?>
<root>
<te>t1</te>
</root>
XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" indent="yes" />
<xsl:template match="root">
<html>
<div>
<xsl:variable name="name1" select="te" />
**
<xsl:value-of select="CtrlList['$name1']" />
**
</div>
<script language="javascript">var List={
"t1":"test"
}</script>
</html>
</xsl:template>
</xsl:stylesheet>
So my objective is get the value of "te" from the XML and map it with the JavaScript object "List" and return the value test while transforming with the XSLT. So i should get the value test as output.
Can anyone figure out what wrong in the XSLT.

When you look at your XSLT, it may seem like there is JavaScript there, but all XSLT sees is that it is outputing an element named "script", with an attribute "language", which contains some text. It is also worth noting that xsl:value-of is used to get the value from the input document, but your script element is actually part of the result tree, and so not accessible to xsl:value-of.
However, it is possible to extend XSLT so it can use javascript functions, but this is very much processor dependant, and you should think of it the same way as embedding JavaScript in HTML. Have a look at this question, as an example
How to include javaScript file in xslt
So, in your case, your XSLT would be something like this (Note this particular example will only work in Mircorsofts MSXML processor)
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="http://mycompany.com/mynamespace"
exclude-result-prefixes="msxsl user">
<xsl:output method="xml" indent="yes" />
<msxsl:script language="JScript" implements-prefix="user">
var List={
"t1":"test"
}
function lookup(key) {
return List[key];
}
</msxsl:script>
<xsl:template match="root">
<html>
<div>
<xsl:variable name="name1" select="te"/>
<xsl:value-of select="user:lookup(string($name1))"/>
</div>
</html>
</xsl:template>
</xsl:stylesheet>
Of course, it might be worth asking why you want to use javascript in your XSLT. It may be possible to achieve the same result using purely XSLT, which would certainly make you XSLT more portable.

Related

is it possible to disable-output-escaping twice in XSLT

I have XML that has encoded HTML data. I am trying to render the data but can't seem to figure out how. Best I can tell is I need to disable-output-escaping="yes" twice but not sure how to do that.
For example, this is a snippet of my XML:
<root>
<node value="&lt;b&gt;body&lt;/b&gt;" />
</root>
My XSLT is outputting HTML. Here is the rendered output (the HTML source) with various options
<xsl:value-of select="#value" /> outputs &lt;b&gt;hi&lt;/b&gt;
<xsl:value-of select="#value" disable-output-escaping="yes" /> outputs <b>hi</b>
I would like it to output <b>hi</b> to the HTML source so its actually rendered as a bolded hi. Does that make sense? Is that possible?
Escaping is the process of turning < into <. If you disable escaping, it will leave < as <. What you want to achieve is to turn < into <, which would normally be called "unescaping".
In the normal course of events, a parser performs unescaping, while a serializer performs escaping. So if you want to unescape characters, you need to put them through a parsing process, which means you need to take the content of the #value attribute and put it through an operation like fn:parse-xml-fragment() in XPath 3.0, or an equivalent extension function in your chosen processor.
Assuming Sharepoint as a Microsoft .NET product uses XslCompiledTransform you could try to implement the unescaping and parsing with extension "script" (C# or VB or JScript.NET code embedded in XSLT) as follows:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="msxsl mf">
<msxsl:script language="C#" implements-prefix="mf">
<msxsl:using namespace="System.IO"/>
public string Unescape(string input)
{
XmlDocument doc = new XmlDocument();
XmlDocumentFragment frag = doc.CreateDocumentFragment();
frag.InnerXml = input;
return frag.InnerText;
}
public XPathNavigator ParseXml(string xmlInput)
{
using (StringReader sr = new StringReader(xmlInput))
{
return new XPathDocument(sr).CreateNavigator();
}
}
</msxsl:script>
<xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<html>
<head>
<title>Test</title>
</head>
<xsl:apply-templates/>
</html>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node">
<div>
<xsl:copy-of select="mf:ParseXml(mf:Unescape(#value))" />
</div>
</xsl:template>
</xsl:stylesheet>
If you have access to an XSLT processor (like any version of Saxon 9.7 or Exselt or the latest Altova or XmlPrime) supporting the XPath 3 functions parse-xml and parse-xml-fragment you can write that template without extension functions (in a version="3.0" stylesheet) as
<xsl:template match="node">
<div>
<xsl:copy-of select="parse-xml(string(parse-xml-fragment(#value)))"/>
</div>
</xsl:template>
Output your result with disable-output-escaping, then treat it again in another XSL with disable-output-escaping.

XML to XSL transformation

I am new to XML. I am trying to convert the following XMl file
<?xml version="1.0"?>
<parent original_id="OI123" id="I123">
<custompanel panel="cp"></custompanel>
</parent>
into the following HTML
<html>
<body><div xmlAttribute="{"original-id":"OI123","id":"I123"}">
<p xmlAttribute={"panel":"cp"}/>
</div>
</body>
</html>
XML tag <parent> should be converted to <div> and <custompanel> should be converted to <p> tag.
I have read the XSTL documentation from W3CSchool but still I am not exactly sure how to approach the problem.Can anyone help me with it?
The custom attribute needs to be stored in xmlAttribute as JSONObject.
After a quick research of the correct syntax I came up with this.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output
method="xml"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
indent="yes"
encoding="utf-8" />
<xsl:template match="parent">
<html>
<body>
<div xmlAttribute="{{'original-id':'{#original_id}','id':'{#id}'}}">
<xsl:apply-templates />
</div>
</body>
</html>
</xsl:template>
<xsl:template match="custompanel">
<p xmlAttribute="{{'panel':'{#panel}'}}" />
</xsl:template>
</xsl:stylesheet>
The tricky part is espacing the {} for the JSON, which we build ourselves. You need two curly braces {{ to have a literal one. Also you need to use single quotes ' inside the attributes as double quotes would be escaped to ". You can access attributes with the #foo selector, but now you need to use actual {} to make the processor recognize it should do something.
I guess that your actual file has more than one <parent>. In that case you need to have a root element around it, and you need to adjust the XSLT. Add another <xsl:template match="/"> and move the HTML frame there.

XSLT transform removes HTML elements from mixed-content

Is it possible for XSLT preserve anchors and other embedded HTML tags within XML?
Background: I am trying to convert an HTML document into XML with an XSL stylesheet using XSLT. The original HTML document had content interspersed with anchor tags (e.g. Some hyperlinks here and there). I've copied that content into my XML, but the XSLT output lacks anchor tags.
Example XML:
<?xml version="1.0" ?>
<observations>
<observation>Hyperlinks disappear.</observation>
</observations>
Example XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/html">
<xsl:output method="html" indent="yes" encoding="UTF-8"/>
<xsl:template match="/observations">
<html>
<body>
<xsl:value-of select="observation"/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Output:
<html xmlns="http://www.w3.org/1999/html">
<body>Hyperlinks disappear.</body>
</html>
I've read a few similar articles on stackoverflow and checked out the Identity transform page on wikipedia; I started to get some interesting results using xsl:copy-of, but I don't understand enough about XSLT to get all of the words and tags embedded within each XML element to appear in the resulting HTML. Any help would be appreciated.
Write a separate template to match a elements, copy their attributes and content.
What is wrong with your approach? In your code,
<xsl:value-of select="observation"/>
simply sends to the output the string value of the observation element. Its string value is the concatenation of all text nodes it contains. But you need not only the text nodes in it, but also the a elements themselves.
The default behaviour of an XSLT processor is to "skip" element nodes, because of a built-in template. So, if you do not mention a in a template match, it is simply ignored and only its text content is output.
Stylesheet
Note: This stylesheet still relies on the default behaviour of the XSLT processor to some extent. The order of events will resemble the following:
The template where match="/observations" is matched. It adds html
and body to the output. Then, a template rule must be found for the
content of observations. A built-in template matches observation,
does nothing with it, and looks for a template to process its content.
For the a element, the corresponding template is matched, with
copies the element and attributes. Finally, a built-in template copies
the text nodes inside observation and a.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/observations">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="a">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XML Output
<html>
<body>Hyperlinks disappear.
</body>
</html>

Issue with xslt transforming xml to output html

I am trying to do a simple transform of XML using XSLT to generate HTML, but I'm having difficulties and I can't seem to figure out what the problem is. Here is a sample of the XML I am working with:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="C:\Users\cgubata\Documents\Digital Measures\jcamp_fac_ex_xslt.xsl"?>
<Data xmlns="http://www.digitalmeasures.com/schema/data" xmlns:dmd="http://www.digitalmeasures.com/schema/data-metadata" dmd:date="2012-02-27">
<Record userId="310106" username="jcamp" termId="453" dmd:surveyId="1154523">
<dmd:IndexEntry indexKey="COLLEGE" entryKey="School of Business" text="School of Business"/>
<dmd:IndexEntry indexKey="DEPARTMENT" entryKey="Accountancy" text="Accountancy"/>
<dmd:IndexEntry indexKey="DEPARTMENT" entryKey="MBA" text="MBA"/>
<PCI id="11454808064" dmd:lastModified="2012-02-08T13:17:39">
<PREFIX>Dr.</PREFIX>
<FNAME>Julia</FNAME>
<PFNAME/>
<MNAME>M.</MNAME>
<LNAME>Camp</LNAME>
<SUFFIX/>
<ALT_NAME>Julia M. Brennan</ALT_NAME>
<ENDPOS/>
All I want to do is have the value for some of the nodes to be displayed in HTML. So for example, I might want the PREFIC, FNAME, LNAME nodes to display as "Dr. Julia Camp" (no quotes - I'll do styling later). Here's the XSL that I am using:
<?xml version="1.0" encoding="utf-8"?><!-- DWXMLSource="jcamp_fac_ex.xml" -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dmd="http://www.digitalmeasures.com/schema/data-metadata">
<xsl:output method="html" encoding="utf-8"/>
<xsl:template match="/">
<xsl:value-of select="/Data/Record/PCI/PREFIX"/>
</xsl:template>
</xsl:stylesheet>
From what I been researching, that should show the value of that PREFIX field. But instead, it is outputting all of the values from all of the nodes (so if there are 4000 nodes with a text value, I am getting 4000 values returned in HTML). My goal will be to pull out the values from certain nodes, and I will probably arrange them in a table.
How do I pull out the values from a specific node? Thanks in advance.
Well, I can't reproduce your symptoms. When I test what you've posted it doesn't produce any output at all. Which looks correct because your xpath is testing the wrong namespace. You need to add in your xslt a namespace-prefix mapping for the http://www.digitalmeasures.com/schema/data namespace, and then use it in the value-of xpath. Like this:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dmd="http://www.digitalmeasures.com/schema/data-metadata"
xmlns:dm="http://www.digitalmeasures.com/schema/data">
<xsl:output method="html" encoding="utf-8"/>
<xsl:template match="/">
<xsl:value-of select="/dm:Data/dm:Record/dm:PCI/dm:PREFIX"/>
</xsl:template>
</xsl:stylesheet>
I'm afraid you've fallen into the number one XSLT trap for beginners: we see this question at least once a day on this forum. Your elements are in a namespace and your stylesheet is trying to match nodes in no namespace.

XSLT parse escaped HTML stored in an attribute and convert that attribute's content into element's content

I'm stuck on what I think should be simple thing to do. I've been looking around, but didn't find the solution. Hope you will help me.
What I have is an XML element with an attribute that contains escaped HTML elements:
<Booking>
<BookingComments Type="RAM" comment="RAM name fred<br/>Tel 09876554<br/>Email fred#bla.com" />
</Booking>
What I need to get is parsed HTML elements and content from the #comment attribute to be a content of element as follows:
<p>
RAM name fred<br/>Tel 09876554<br/>Email fred#bla.com
<p>
Here is my 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" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="xs fn" version="1.0">
<xsl:output method="html" doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"
doctype-system="http://www.w3.org/TR/html4/loose.dtd" encoding="UTF-8" indent="yes" />
<xsl:template name="some-template">
<p>Some text</p>
<p>
<xsl:copy-of
select="/Booking/BookingComments[lower-case(#Type)='ram'][1]/#comment"/>
</p>
</xsl:template>
</xsl:stylesheet>
I've read that copy-of is a good way to restore escaped HTML elements back to proper elements. In this specific case, because it's initially an attribute the copy-of translates it into attribute as well. So I get:
<p comment="RAM name fred<br/>Tel 09876554<br/>Email fred#bla.com"></p>
Which isn't what I want.
If I use apply-templates instead of copy-of, as in:
<p>
<xsl:apply-templates select="/Booking/BookingComments[lower-case(#Type)='ram'[1]/#comment"/>
</p>
I get p's content simply as text, not restored HTML elements.
<p>RAM name fred<br/>Tel 09876554<br/>Email fred#bla.com</p>
I'm sure I'm missing something obvous. I would really appreciate any help and tips!
I would recommend using a dedicated template:
<!-- check if lower-casing #Type is really necessary -->
<xsl:template name="BookingComments[lower-case(#Type)='ram']/#comment">
<p>
<xsl:value-of select="." disable-output-escaping="yes" />
</p>
</xsl:template>
This way you could simply apply templates to the attribute. Note that disabling output escaping has the potential to generate ill-formed output.
You could bind an extension function parse() which parses a string into a nodeset. The exact mechanism will depend on your XSLT engine.
In Xalan, we can take the following static method:
public class MyExtension
{
public static NodeIterator Parse( string xml );
}
and use it like so:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:java="http://xml.apache.org/xalan/java"
exclude-result-prefixes="java"
version="1.0">
<xsl:template match="BookingComments">
<xsl:copy-of select="java:package.name.MyExtension.Parse(string(#comment))" />
</xsl:template>
</xsl:stylesheet>