I am transforming XML files with XSL to HTML files. Is it possible to embed the original XML file in the HTML output? When yes, how is that possible?
Update 1: To make my need better understandable: In my HTML file, I want a form where I can download the original XML file. Therefore I have to embed the original XML file into my HTML file (e.g. as a hidden input field)
Thanks
If you want to copy the nodes through you can simply do <xsl:copy-of select="/"/> where you want to insert them, however, putting arbitrary XML nodes into HTML does not make sense usually. If you want to serialize an XML document to plain text to render it then you can use solutions like http://lenzconsulting.com/xml-to-string/, for instance:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="http://lenzconsulting.com/xml-to-string/xml-to-string.xsl"/>
<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>
<body>
<section>
<h1>Test</h1>
<xsl:apply-templates/>
<section>
<h2>Source</h2>
<pre>
<xsl:apply-templates mode="xml-to-string"/>
</pre>
</section>
</section>
</body>
</html>
</xsl:template>
<xsl:template match="data">
<ul>
<xsl:apply-templates/>
</ul>
</xsl:template>
<xsl:template match="item">
<li>
<xsl:apply-templates/>
</li>
</xsl:template>
</xsl:transform>
transforms an XML input like
<data>
<item att="value">
<!-- comment -->
<foo>bar</foo>
</item>
</data>
into the HTML
<!DOCTYPE html
PUBLIC "XSLT-compat">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test</title>
</head>
<body>
<section>
<h1>Test</h1>
<ul>
<li>
bar
</li>
</ul>
<section>
<h2>Source</h2><pre><data>
<item att="value">
<!-- comment -->
<foo>bar</foo>
</item>
</data></pre></section>
</section>
</body>
</html>
Related
Sorry, this is a really novice question. My real problem involves translating HTML to Open Office XML, but this illustrates the issue I am seeing. I want to make sure the "b" node is ignored in my processing, i.e. not get the 123 at the end of the results output.
XML:
<?xml version="1.0"?><?xml-stylesheet type="text/xsl"?>
<a>
<hello-world>
<greeter>An XSLT Programmer</greeter>
<greeting>Hello, World!</greeting>
</hello-world>
<b>123
</b>
</a>
XSLT:
<?xml version="1.0"?><xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="hello-world">
<HTML><HEAD><TITLE></TITLE></HEAD><BODY><H1>
<xsl:value-of select="greeting"/>
</H1>
<xsl:apply-templates select="greeter"/>
</BODY></HTML>
</xsl:template>
<xsl:template match="greeter">
<DIV>from <I><xsl:value-of select="."/></I></DIV>
</xsl:template>
</xsl:stylesheet>
Results:
<HTML>
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<TITLE></TITLE>
</HEAD>
<BODY>
<H1>Hello, World!</H1>
<DIV>from <I>An XSLT Programmer</I></DIV>
</BODY>
</HTML>
123
I see you added an answer, but thought I could add more information.
Your first attempt was good, you could have simply added another template to ignore the "b" nodes.
<xsl:template match="b"/>
What was happening is that the XSLT built-in template rules include by default a template that copies the text of any node that's not explicitely matched by your templates.
Reference: docstore.mik.ua/orelly/xml/xmlnut/ch08_07.htm
See the output of your transformation with the added template: https://xsltfiddle.liberty-development.net/aixRus
The issue was that I wasn't selecting the whole document to begin with. If I change the xslt as follows, it then works
<?xml version="1.0"?><xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/*">
<xsl:apply-templates select='hello-world'/>
</xsl:template>
<xsl:template match="hello-world">
<HTML><HEAD><TITLE></TITLE></HEAD><BODY><H1>
<xsl:value-of select="greeting"/>
</H1>
<xsl:apply-templates select="greeter"/>
</BODY></HTML>
</xsl:template>
<xsl:template match="greeter">
<DIV>from <I><xsl:value-of select="."/></I></DIV>
</xsl:template>
</xsl:stylesheet>
I'm trying to transform some xml with content encoded as html entities. I want to output the entity content as valid html.
The xml is like this ..
<?xml version="1.0" encoding="UTF-8"?><memo Version="1.0">
<header>
<meta title="==PROGRAMMING=="/>
<meta favourite="false"/>
<meta uuid="85f94ab2-77a8-XXXXXXXXXXXXXXX"/>
<meta createdTime="1551038092051"/>
</header>
<contents>
<content><p value="memo2" >=====</p><p>https://medium.freecodecamp.org/</p><p>=====</p>
</content>
</contents>
</memo>
I have some xslt as so..
xslt_src = '''
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<head>
<xsl:apply-templates select="memo/header/meta"/>
</head>
<body>
<xsl:apply-templates select="memo/contents"/>
</body>
</html>
</xsl:template>
<xsl:template match="memo/header/meta">
<xsl:apply-templates select="#title"/>
</xsl:template>
<xsl:template match="memo/contents">
<div class='content'>
<xsl:value-of select="content/text()"/>
</div>
</xsl:template>
<xsl:template match="#title">
<span id='title'>
<xsl:value-of select="."/>
</span>
</xsl:template>
</xsl:stylesheet>
'''
I process it with lxml in Python...
_________________________________________________________________python
from lxml import etree
xslt = etree.XML(xslt_src)
transform = etree.XSLT(xslt)
src = open('simple.xml').read()
xml = etree.XML(str.encode(src))
result = transform(xml)
root = result.getroot()
print('-----------------------out 1')
print(etree.tostring(root, pretty_print=True).decode('utf-8'))
print('-----------------------out 2')
content = root.xpath('/html/body/div/text()')
print(content[0])
==============================================================
etree.tostring(root) prints the structured document but leaves the html entities as encoded in the original xml.
-----------------------out 1
<html>
<head>
<span id="title">==PROGRAMMING==</span>
</head>
<body>
<div class="content"><p value="memo2" >=====</p><p>https://medium.freecodecamp.org/</p><p>=====</p>
</div>
</body>
</html>
but if I print root.xpath('/html/body/div/text()')[0] (the node with the html content) I get what I want...
-----------------------out 2
<p value="memo2" >=====</p><p>https://medium.freecodecamp.org/</p><p>=====</p>
=======================================================================
My question is: how can I make etree.tostring(root) replace the html entities with valid html, as is printed when I use the text attribute directly?
Cheers!
bitrat
Instead of:
<xsl:value-of select="content/text()"/>
try:
<xsl:value-of select="content" disable-output-escaping="yes"/>
I've the below XML.
<chapter num="1">
<section level="sect2">
<page>22</page>
</section>
<section level="sect3">
<page>23</page>
</section>
</chapter>
here I'm trying to get the first occurrence of <page>.
I'm using the below XSLT.
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ntw="Number2Word.uri" exclude-result-prefixes="ntw">
<xsl:output method="html"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="ThisDocument" select="document('')"/>
<xsl:template match="/">
<xsl:text disable-output-escaping="yes"><![CDATA[<!DOCTYPE html>]]></xsl:text>
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="chapter">
<section class="tr_chapter">
<xsl:value-of select="//page[1]/text()"/>
<div class="chapter">
</div>
</section>
</xsl:template>
</xsl:stylesheet>
but the output that I get all the page valyes printed. I only want the first one.
Current output.
<!DOCTYPE html>
<html>
<body>
<section class="tr_chapter">2223
<div class="chapter">
</div>
</section>
</body>
</html>
the page values are printed here after <section class="tr_chapter">, i want only 22 but I'm getting 2223
here I'm using //page[1]/text(), because I'm not sure that the page comes within the section, it is random.
please let me know how I can get only the first page value.
here is the transformation http://xsltransform.net/3NzcBsR
Try:
<xsl:value-of select="(//page)[1]"/>
http://xsltransform.net/3NzcBsR/1
Note that this gets the value of the first page element in the entire document.
If you want to search the contents of the chapter context element in your template for the first page descendant then use <xsl:value-of select="descendant::page[1]"/> or <xsl:value-of select="(.//page)[1]"/>.
I'm just trying to select the node 'productgroep' with attribute value 'cd'. This is not working and I really don't understand why, I searched for answers but didn't find any.
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="Oefening_8.xsl"?>
<catalogus>
<!-- cd catalogus -->
<productgroep type="cd">
<item referentienummer="7051444" catalogusnummer="1800022" EAN="0025218000222">
...
</productgroep>
<productgroep type="film">
<item referentienummer="8051445" catalogusnummer="2800023" EAN="5051888073650">
....
</productgroep>
</catalogus
XSL:
<?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"/>
<xsl:template match="/">
<html>
<head>
<title>Oefening_8.xsl</title>
<meta charset="utf-8"/>
<link href="Oefening_8.css" type="text/css" rel="stylesheet"/>
</head>
<body>
<h1></h1>
<xsl:template match="productgroep[#type='cd']">
</xsl:template>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
An <xsl:template/> cannot be a child of a <xsl:template/>, so your stylesheet is currently invalid and probably giving an error somewhere, depending on how you are using the XML and XSL.
One solution is to create the separate <xsl:template>s and use <xsl:apply-templates /> to processes the children of the source element.
<xsl:template match="/">
<html>
<head>
<title>Oefening_8.xsl</title>
<meta charset="utf-8"/>
<link href="Oefening_8.css" type="text/css" rel="stylesheet"/>
</head>
<body>
<h1></h1>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<xsl:template match="productgroep[#type='cd']">
<xsl:value-of select="item/#catalogusnummer"/> <!-- print #catalogusnummer for example -->
</xsl:template>
As #andyb pointed out, you can't have a template inside a template. It may be that you meant to use xsl:apply-templates where you have xsl:template, but that wouldn't have worked either with the path you used, because the current context there is the node above catalogus. Your options are to change the initial xsl:template to select the root element with either:
or
or to use the full path in the xsl:apply-templates:
I prefer the first option:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"/>
<xsl:template match="/*">
<html>
<head>
<title>Oefening_8.xsl</title>
<meta charset="utf-8"/>
<link href="Oefening_8.css" type="text/css" rel="stylesheet"/>
</head>
<body>
<h1></h1>
<xsl:apply-templates select="productgroep[#type='cd']" />
</body>
</html>
</xsl:template>
</xsl:stylesheet>
XML:
<?xml version="1.0" encoding="UTF-9" ?>
<mailAndMessageSettings>
<settings>
<add key="Url" value=""/>
<add key="UserName" value=""/>
<add key="Password" value=""/>
</settings>
<mail>
<subject>
Mp3 Submission
</subject>
<body>
<![CDATA[
<meta http-equiv="Content-Type" content="text/html; charset="utf-8""/>
<head></head>
<body>
<p>Hi,</p>
<p>Please find the attached mp3... :-)</p>
<p>here</p>
<p>Regards,</br>
Pete</p>
</body>
</html>
]]>
</body>
</mail>
</mailAndMessageSettings>
XSLT:
<xsl:template match="/">
<xsl:value-of select="/mailAndMessageSettings/mail" disable-output-escaping="yes"/>
</xsl:template>
Expected output:
<mail>
<subject>
Mp3 Submission
</subject>
<body>
<![CDATA[
<meta http-equiv="Content-Type" content="text/html; charset="utf-8""/>
<head></head>
<body>
<p>Hi,</p>
<p>Please find the attached mp3... :-)</p>
<p>here</p>
<p>Regards,</br>
Pete</p>
</body>
</html>
]]>
</body>
</mail>
I want to add an attribute "onclick" on "here" in a CDATA and getting the whole "mail" node? Is it really possible? Can anyone help me with this stuff? Thanks in advance.
Your help would be greatly appreciated :)
There are no nodes or tags inside a CDATA section. CDATA means "character data". The only reason for putting stuff inside CDATA is to say "The stuff in here might look like markup, but I don't want it treated as markup; just treat it as text". So if you want to treat it as markup, don't put it in CDATA.
You'll have to resort to string manipulation, like so:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="body[contains(.,'>here</a>')]">
<xsl:value-of disable-output-escaping="yes" select="concat(
'<![CDATA[',
substring-before(.,'>here</a>'),
' onclick="myfunction();">here</a>',
substring-after(.,'>here</a>'),
']]>'
)"/>
</xsl:template>
</xsl:stylesheet>
But is there a reason why the mail body has to be CDATA in the first place?