XML and XSL format linking - html

Hi Im having trouble linking my XML and XSLT, My XML is long but heres a extract, The problem is my XSLT is not formatting it, I am trying to get my XML displayed under each other with a title. forgive me but english is not my first language
XML:
<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet type="text/xsl" href="Product_List.xsl"?>
<ProductCatalogue>
<drinks>
<product>
<name Product_Code="D001">Lemonade</name>
<price>6.50</price>
<amount>20</amount>
<supplier>Coca-Cola</supplier>
</product>
</drinks>
</ProductCatalogue>
XSLT
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h3>Product List</h3>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="drinks">
<div style="color:#0000FF">
<h3>
<xsl:value-of select="name"/>
</h3>
</div>
<div>
<xsl:value-of select="name#Product_code"/>
</div>
<p>Price : <xsl:value-of select="price"/></p>
<p>Supplier : <xsl:value-of select="supplier"/></p>
<p>Amount : <xsl:value-of select="amount"/></p>
</xsl:template>
</xsl:stylesheet>

I believe its a problem with my templates but im not sure how its fixed
Yes, there is indeed a problem with your templates. The easiest way to make your transformation actually output the values is to change the second template match, originally
<xsl:template match="drinks">
to
<xsl:template match="product">
Inside this template, you are selecting elements like name and price, which are child elements of product, not of drinks.
Also, change
<xsl:value-of select="name#Product_code"/>
to
<xsl:value-of select="name/#Product_Code"/>
XML and all the technologies related to it are case-sensitive - Product_code is not the same as Product_Code.
Then, the output will be
<html>
<body>
<h3>Product List</h3>
<div style="color:#0000FF">
<h3>Lemonade</h3>
</div>
<div>D001</div>
<p>Price : 6.50</p>
<p>Supplier : Coca-Cola</p>
<p>Amount : 20</p>
</body>
</html>

Related

How can I fix my XSLT so that it displays my XML as pictured?

I'm new to XML and hoping for a little feedback. I am trying to display my XML so that it looks like this:
How I hope to get my XML to display
I can't seem to get the elements to display in the templates. (Clearly, I am not building them correctly). How would I get the title element (Koha) to show up bold and larger as it does in the example? I'm just feeling a bit stuck and my professor is busy and I was hoping someone might be able to offer suggestions about what to do next?
my XML:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<digitalLibrarySystem xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.pages.drexel.edu/~eom25/657/diglibschema/digitalLibrarySystem.xsd">
<systemMetadata>
<title>Koha</title>
<creator>by Katipo Communications</creator>
<subject>public libraries</subject>
<subject>bibliographic managemen</subject>
<subject>distributed library systems</subject>
<description>Koha was one of the the first open-source Integrated Library Systems. It is used and maintained by the worldwide library community.</description>
<date>2000</date>
<type>ILS</type>
<rights>Open-source</rights>
<identifier xlink:type="simple" xlink:href="http://http://www.koha.org/">http://www.http://www.koha.org/</identifier>
</systemMetadata>
<aboutRecord>
<recordCreator>Matthew Weidemann</recordCreator>
<creationDate>May 6, 2018</creationDate>
</aboutRecord>
My XSLT so far:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h1>"font-weight:bold"><xsl:value-of select="title"/></h1>
<h2>by <xsl:value-of select="systemMetadata/creator"/></h2>
<h3><xsl:value-of select="systemMetadata/subject"/></h3>
<br/>
<p>
<h4><xsl:value-of select="systemMetadata/description"/></h4>
<br/>
</p>
<h5><xsl:value-of select="systemMetadata/rights"/></h5>
<br/>
<h6><i>Record created by <xsl:value-of
select="aboutRecord/recordCreator"/> on
<xsl:value-of select="aboutRecord/creationDate"/></i></h6>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
I am confused about the XPaths I think and Any suggestions are helpful.
I reorganized your XSLT file a little bit.
You would have it a lot easier if you start to correctly indent the files.
And have a look at the differences to begin to comprehend how XSLT works.
So here is your (slightly modified) XSLT-1.0 file which brings you closer to your goal:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- Create HTML header and stuff -->
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates /> <!-- Apply the other templates -->
</body>
</html>
</xsl:template>
<!-- Process all systemMetadata sub-nodes -->
<xsl:template match="systemMetadata">
<h1>
<b><xsl:value-of select="title"/></b>
</h1>
<h2>
<xsl:value-of select="creator"/>
</h2>
<h2>
<xsl:value-of select="subject"/>
</h2>
<br/>
<p>
<h3>
<xsl:value-of select="description"/>
</h3>
</p>
<h3>
<xsl:value-of select="rights"/>
</h3>
</xsl:template>
<!-- Process all aboutRecord sub-nodes -->
<xsl:template match="aboutRecord">
<h3>
<i>Record created by <xsl:value-of
select="recordCreator"/> on <xsl:value-of select="creationDate"/></i>
</h3>
</xsl:template>
</xsl:stylesheet>
Now you can modify it to pretty print the results.
If you want to create the nice border, change the first template to
<!-- Create HTML header and stuff -->
<xsl:template match="/">
<html>
<body>
<table border="1">
<tr><td><xsl:apply-templates /></td></tr>
</table>
</body>
</html>
</xsl:template>

Using XSLT to span text between two empty nodes

I have an XML file with a series of pairings like the following:
<metamark function="let-stand" spanTo="#meta-93"/>some text between the two empty nodes<anchor xml:id="meta-93"/>
In other words, the text is always preceded with a metamark tag with #function='let-stand' and a spanTo with a unique value. And the text is always followed with an anchor tag whose #xml:id value match that of the #spanTo value on the metamark.
When transforming such text via XSLT into HTML, I would like to wrap it in a span tag as follows:
<span class="dotted">some text between the two empty nodes</span>
How can I achieve this? Note that the text between the two empty nodes will always be siblings. The value I've put on the span #class is arbitrary. I'm just using "dotted" for demonstration purposes here.
The basic idea is that for each metamark:
create span tag,
get following siblings of the current metamark,
which as a following sibling have anchor tag with proper id (end point, exclusive),
and apply templates to them.
Of course, you have to block "normal" template application within the parent tag of your metamark tags.
Try the following transformation:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html" doctype-public="XSLT-compat"
encoding="UTF-8" indent="yes" />
<xsl:template match="metamark">
<xsl:element name="span">
<xsl:attribute name="class" select="'dotted'"/>
<xsl:variable name="termId" select="substring(#spanTo, 2)"/>
<xsl:variable name="srcRange" select="following-sibling::node()
[following-sibling::anchor[#xml:id=$termId]]"/>
<xsl:apply-templates select="$srcRange"/>
</xsl:element>
<xsl:text>
</xsl:text>
</xsl:template>
<!-- In "main" process only "metamark" tags -->
<xsl:template match="main">
<xsl:apply-templates select="metamark"/>
</xsl:template>
<!-- HTML envelope -->
<xsl:template match="/">
<html>
<body>
<xsl:text>
</xsl:text>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<!-- Identity transform -->
<xsl:template match="#*|node()">
<xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy>
</xsl:template>
</xsl:transform>
I tried it for the following XML sample:
<?xml version="1.0" encoding="utf-8"?>
<main>
<metamark function="let-stand" spanTo="#meta-93"/>Aaaaaa bbbbbbb<anchor xml:id="meta-93"/>
<metamark function="let-stand" spanTo="#meta-94"/>Eeeeee <b>bbb</b> ccc<anchor xml:id="meta-94"/>
<metamark function="let-stand" spanTo="#meta-95"/>Ffffff bbbbbbb<anchor xml:id="meta-95"/>
</main>
and got result:
<!DOCTYPE html PUBLIC "XSLT-compat">
<html>
<body>
<span class="dotted">Aaaaaa bbbbbbb</span>
<span class="dotted">Eeeeee <b>bbb</b> ccc</span>
<span class="dotted">Ffffff bbbbbbb</span>
</body>
</html>

XML to XSL Error loading stylesheet: Parsing an XSLT stylesheet failed

I'm getting this error when trying to convert a XML document with XSL. I've only just started coding with XML, so I am sure I am missing something simple, but cant seem to find much information about it online.
Booklist.XML
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="booklist.xsl"?>
<CATALOG>
<BOOK>
<NAME>
<TITLE>Caring for Sheep</TITLE>
</NAME>
<PAGES> 60 </PAGES>
<PRICE>$34.99</PRICE>
</BOOK>
</CATALOG>
And my XSL File:
Booklist.XSL
<?xml version="1.0"?>
<body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE">
<xsl:for-each select="CATALOG/BOOK/NAME">
<div style="background-color:teal;color:white;padding:4px">
<xsl:value-of select="name">;
</div>
</xsl:for-each>
<xsl:for-each select="CATALOG/BOOK">
<div style="background-color:teal;color:white;padding:4px">
</div>
</xsl:for-each>
</body>
Can anyone see an error here?
You're sort of mixing the Literal Result Element as Stylesheet simplified syntax with the regular syntax by putting a literal result element <body> outside any template, yet not at the top level. If you want to use this simplified syntax, get rid of the <xsl:stylesheet> and <xsl:output> elements, so that <body> is at the top level.
Also, XML and XPath are case-sensitive with regard to element names, so you'll need to fix the inconsistency between e.g. "catalog" and <CATALOG>.
Well, if the for some reasons which are hard to figure out the simplified syntax doesn't work for you I would suggest using the "normal coding", which would be something like this in your case:
<?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="1.0">
<xsl:template match="/">
<body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE">
<xsl:for-each select="/CATALOG/BOOK/NAME">
<div style="background-color:teal;color:white;padding:4px">
<xsl:value-of select="name"/>
</div>
</xsl:for-each>
<xsl:for-each select="/CATALOG/BOOK">
<div style="background-color:teal;color:white;padding:4px">
</div>
</xsl:for-each>
</body>
</xsl:template>
</xsl:stylesheet>

Adding HTML tags with XSLT on the fly

I have an XML document containing this:
<d1/>
<p1>...</p1>
<p2>...</p2>
<d2/>
<p3>...</p3>
<d3/>
Where pn are elements with possibly subelements and other stuff, and dn indicates where an HTML DIV tag wrapping the p tags should begin, but without a corresponding closing tag, this is only indicated implicitly by the next dn tag. The desired HTML output is this:
<div>
<p1>...</p1>
<p2>...</p2>
</div>
<div>
<p3>...</p3>
</div>
I have written an XSLT to introduce the <div> and </div> tags on the fly, using the following:
<xsl:text disable-output-escaping="yes"><div></xsl:text>
and
<xsl:text disable-output-escaping="yes"></div></xsl:text>
and this works on Safari, but it fails on FireFox, which makes me suspect that it's not the right way to do it.
Do you have a better idea that will work on every browser?
Thanks a lot in advance.
Firefox does not support disable-output-escaping because it does not serialize the result tree. The problem is a grouping problem, one way to solve it is to use a key:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:key name="group" match="body/*[not(starts-with(local-name(), 'd'))]" use="generate-id(preceding-sibling::*[starts-with(local-name(), 'd')][1])"/>
<xsl:template match="body">
<xsl:copy>
<xsl:apply-templates select="*[starts-with(local-name(), 'd')]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[starts-with(local-name(), 'd')]">
<div>
<xsl:copy-of select="key('group', generate-id())"/>
</div>
</xsl:template>
</xsl:transform>
That would create an empty div however at the end of your sample, so you might want to change the last template to
<xsl:template match="*[starts-with(local-name(), 'd')]">
<xsl:if test="key('group', generate-id())">
<div>
<xsl:copy-of select="key('group', generate-id())"/>
</div>
</xsl:if>
</xsl:template>
You could use a technique known as "sibling recursion".
Given a well-formed input such as:
XML
<root>
<d1/>
<p1>a</p1>
<p2>b</p2>
<d2/>
<p3>c</p3>
<d3/>
</root>
the following stylesheet:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/root">
<body>
<xsl:apply-templates select="*[starts-with(name(), 'd')][position()!=last()]"/>
</body>
</xsl:template>
<xsl:template match="*[starts-with(name(), 'd')]">
<div>
<xsl:apply-templates select="following-sibling::*[1][not(starts-with(name(), 'd'))]"/>
</div>
</xsl:template>
<xsl:template match="/root/*[not(starts-with(name(), 'd'))]">
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::*[1][not(starts-with(name(), 'd'))]"/>
</xsl:template>
</xsl:stylesheet>
will return:
<body>
<div>
<p>a</p>
<p>b</p>
</div>
<div>
<p>c</p>
</div>
</body>

XSLT: all elements to div elements with class attribute = original element name

I've got a xml in the following form (but much larger..)
<entry>
<lemma>coaster</lemma>
<sense>
<trans>Untersetzer</trans>
</sense>
</entry>
What I want to get by xsl-transformation is this:
<div class="entry">
<div class="lemma>coaster</div>
<div class="sense">
<div class="trans">Untersetzer</div>
</div>
</div>
Not that complicated: Transform all elements to div elements with class attribute = original element name.
Could anybody please give me a hint how an appropriate XSL should look like?
Thanks!
You can do that (XSLT 1.0) :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="*">
<div class="{local-name()}">
<xsl:apply-templates/>
</div>
</xsl:template>
</xsl:stylesheet>
Note that the stylesheet skip the attributes it encounters.
EDIT after comment
If you want to keep attributes, you just have to skip any class attributes (because you create a new one). For example like this :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="*">
<div class="{local-name()}">
<xsl:apply-templates select="node()|#*"/>
</div>
</xsl:template>
<xsl:template match="#*">
<xsl:if test="name() != 'class'">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>