How to read namespace declarations using XSLT? - xslt

I have to trasform the raw response of any OData feed (ATOM) in the form of a tree with expandable/collapsable nodes. For this purpose I am converting the raw response into HTML using XSLT transformation.
The problem is that response from some services have the feed element with namespace declarations as attributes. (eg: feed xmlns:d= ..., xmlns:m= ...).In my final output these namespace declarations are not displayed.
The XSLT processor ignores them while processing the attributes.(I am using the XPath expression "#*".) Is there a way to extract them using XSLT and display the namespace declaration content as-is in the trasformed output ?
Note that I get to know about these namespace declaration attributes at runtime in the OData response. I have no information before the query executes.
UPDATE:
Input : (RAW XML Entry)
<?xml version="1.0" encoding="utf-8"?><entry xml:base="http://services.odata.org/Northwind/Northwind.svc/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><id>http://services.odata.org/Northwind/Northwind.svc/Regions(1)</id><category term="NorthwindModel.Region" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /><link rel="edit" title="Region" href="Regions(1)" /><link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Territories" type="application/atom+xml;type=feed" title="Territories" href="Regions(1)/Territories" /><title /><updated>2014-03-17T10:24:14Z</updated><author><name /></author><content type="application/xml"><m:properties><d:RegionID m:type="Edm.Int32">1</d:RegionID><d:RegionDescription xml:space="preserve">Eastern </d:RegionDescription></m:properties></content></entry>
Desired Output: (The same ATOM entry,as a XML tree, pretty printed with expandable/collapsable nodes)
-<entry xml:base="http://services.odata.org/Northwind/Northwind.svc/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
-<id>
http://services.odata.org/Northwind/Northwind.svc/Regions(1)
</id>
<category term="NorthwindModel.Region" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/>
<link rel="edit" title="Region" href= "Regions(1)" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Territories" type="application/atom+xml;type=feed" title="Territories" href= "Regions(1)/Territories" />
<title/>
<updated>2014-03-17T10:06:25Z</updated>
-<author>
<name/>
</author>
-<content type="application/xml">
-<m:properties>
<d:RegionID m:type="Edm.Int32">1</d:RegionID>
<d:RegionDescription xml:space="preserve">Eastern </d:RegionDescription>
</m:properties>
</content>
</entry>
Output which I am getting.
-<entry xml:base="http://services.odata.org/Northwind/Northwind.svc/">
-<id>
http://services.odata.org/Northwind/Northwind.svc/Regions(1)
</id>
<category term="NorthwindModel.Region" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/>
<link rel="edit" title="Region" href= "Regions(1)" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Territories" type="application/atom+xml;type=feed" title="Territories" href= "Regions(1)/Territories" />
<title/>
<updated>2014-03-17T10:06:25Z</updated>
-<author>
<name/>
</author>
-<content type="application/xml">
-<m:properties>
<d:RegionID m:type="Edm.Int32">1</d:RegionID>
<d:RegionDescription xml:space="preserve">Eastern </d:RegionDescription>
</m:properties>
</content>
</entry>
Please note the missing name space declarations in the output's "entry" root element.
The output is a HTML which displays pretty-printed xml, with expandable/collapsable nodes and since it should display the data as-is, namespace declarations are required to be displayed in the output HTML.
Clicking on the "-" symbols collapses the nodes.

If a declaration is already in scope (remember, namespace bindings are inherited to children), it will not need to be redeclared and most XML serializers will not generate it. You haven't shown us an example yet, but I'd bet your output is fine as it is.

Namespace declarations in your source XML appear in the XPath data model as namespace nodes (not attribute nodes).
You need to make clear what you want to do with the namespaces. You're saying that you are generating HTML, but you also say you want to copy the namespaces to the output. That seems inconsistent. Show us you input and desired output.

I haven't managed to spot the difference between your actual output and your desired output (never was very good at "spot the ball" competitions), but from your revised description of the problem it sounds as if you should be using the namespace axis to find the in-scope namespaces for an element (in the same way as you are currently using the attribute axis).
The only tricky part is that the namespace axis will give you all the namespaces for an element and you probably only want to show those that are different from the namespaces of the parent element.
The details depend on whether you are using XSLT 1.0 or 2.0 - you need to tell us!

Related

XSLT copy from external document

In XSLT 2.0 I am transforming a tei-xml document into HTML. In that transformationI need content from another document: I want to copy/transform a small set of nodes from the second document into the HTML output.
While processing the principal tei document I get the id and assign it to a variable:
<xsl:variable name="licenseid" select="./replace(#corresp,'#','')"/>
Then I go out to the other document and fetch the node using the variable, with the returned node assigned to a variable:
<xsl:variable name="licenseloc" select="doc(concat($somepath,'includes_sourcedesc.xml'))//tei:list[#type='copyright_type']/tei:item[#xml:id=$licenseid]"/>
This node I obtain looks like this:
<list type="copyright_type">
<item xml:id="copyright-cc-by-nc-sa-4.0">
<desc xml:lang="en">This work is made by available the author under the
<ref target="http://creativecommons.org/licenses/by-nc-sa/4.0/">Creative Commons Attribution-NonCommercial-ShareAlike
4.0 International License</ref>.</desc>
</item>
</list>
And I want to transform it (from desc) to this:
<span>This work is made by available by the author under the
<a href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Creative Commons Attribution-NonCommercial-ShareAlike
4.0 International License</a>.</span>
If this were in my 'current' tei document I would handle it through templates, but I'm unsure how to copy and transform the nested layers from within a different 'current' document.

XPath selector not working during PDF transformation

I have a DITA bookmap where I am storing image paths:
<bookmap>
<bookmeta>
<data id="productLogo">
<image href="images/_notrans/frontcover/productLogo.svg" />
</data>
<data id="productPhoto" >
<image href="images/_notrans/frontcover/productPhoto.jpg" />
</data>
</bookmeta>
</bookmap>
Then I attempt to grab the href values by data[#id]:
<xsl:variable name="productLogo"><xsl:value-of select="//data[#id='productLogo']/image/#href" /></xsl:variable>
<xsl:variable name="productPhoto"><xsl:value-of select="//data[#id='productPhoto']/image/#href" /></xsl:variable>
(These XPath expressions match the href when I test against my bookmap in Oxygen.)
During transformation I output:
<xsl:message>productPhoto: <xsl:value-of select="$productPhoto"/></xsl:message>
The value-of is always empty.
However, everything works as expected if I replace the id attribute with numbers:
<xsl:variable name="productLogo"><xsl:value-of select="//data[1]/image/#href" /></xsl:variable>
<xsl:variable name="productPhoto"><xsl:value-of select="//data[2]/image/#href" /></xsl:variable>
What am I doing wrong that's preventing using #id="whatever"?
The XSLT is not applied directly over the Bookmap contents, it is applied over an XML document which contains the bookmap with all topic references expanded in it and with some preprocessing applied to it.
If you set the "clean.temp" parameter to "no" you will find in the temporary files folder a file called something like "mapName_MERGED.xml", that is the XML document over which the XSLT is applied and as you will see in it, all IDs have been changed to be unique in the context of the entire XML document.
When usually working with data elements you should set the #name attribute to them like:
<data name="productLogo">
and match that name in the XSLT code.
There are examples of using "data" in the DITA 1.2 specs as well:
http://docs.oasis-open.org/dita/v1.2/os/spec/langref/data.html#data
Another option, depending on your needs, is to develop a naming convention for the product photos and use the element to build the URI. As the product logo shouldn't change for a product family, it wouldn't hurt to hard-code that in the XSLT code.

Getting the value of an attribute in an XML document using XSL

I'm trying to get the value of iWantToGetThis.jpg and put it into an <img> during my XSL transformation. This is how my xml is structures:
<article>
<info>
<mediaobject>
<imageobject>
<imagedata fileref='iWantToGetThis.jpg'>
Here's what I've come up with for the XSL:
<xsl:template name="user.header.content">
<xsl:stylesheet xmlns:d='http://docbook.org/ns/docbook'>
<img><xsl:attribute name="src">../icons/<xsl:value-of select='ancestor-or-self::d:article/info/mediaobject/imageobject/imagedata/#fileref' /></xsl:attribute></img>
</xsl:stylesheet>
</xsl:template>
The image is being added to the output, but the src attribute is set to "../icons/", so I'm assuming it's not finding the fileref attribute in the XML. This looks perfectly valid to me, so I'm not sure what I'm missing.
I am not sure how you can get anything back at all, because that does not look like a valid XSLT document (I would expect the error "Keyword xsl:stylesheet may not contain img.").
However, it may be you are just showing a fragment of the code. If this is the case, your issue may be that you have only specified the namespace for the article element, when you really need to specify it for all elements in your xpath. Try this
<xsl:value-of
select="ancestor-or-self::d:article/d:info/d:mediaobject/d:imageobject/d:imagedata/#fileref"/>
Another possible problem may be because you are using the 'ancestor-or-self' xpath axis to find the attribute. This would only work if your current context was already on the article element, or one of its descendants.
As a side note, you can simplify the code by making use of Attribute Value Templates here
<img src="../icons/{ancestor-or-self::d:article/d:info/d:mediaobject/d:imageobject/d:imagedata/#fileref}" />

Saxon Transformerfactory placing unneceary xmlns:xsd="http://www.w3.org/2001/XMLSchema" in transformer output

I am using Sax transformer factory to do an XSLT transformation on large set of xsd files, so a particular line the xslt is as follows.
<xsl:result-document href="{$fileName}"
doctype-public="-//OASIS//DTD DITA Reference//EN"
doctype-system="reference.dtd">
<reference id="{$guid}" xml:lang="EN-US" outputclass="landscape">
<title>
<xsl:value-of select="$typeName"/>
</title>
<abstract>....
the reference tag being the root of the document, but the result has an unwanted xmlns:xsd attribute shown below.
...<reference xmlns:xsd="http://www.w3.org/2001/XMLSchema"
id="RANDOM-ID".....
this additional attribute is causing problems with parser that uses the transformed xml.
is this an issue with the XSLT or with SAXON api, how can i avoid this?
By default the xsl transformation will copy namespaces that are defined in the stylesheet to the output document. You can exclude this namespace by specifying the exclude-result-prefixes on the xsl:stylesheet or the reference element with a value of "xsd".
Here is the relevant part of the xslt sepcification:
The created element node will also have a copy of the namespace nodes that were present on the element node in the stylesheet (...)
A namespace URI is designated as an excluded namespace by using an exclude-result-prefixes attribute on an xsl:stylesheet element or an xsl:exclude-result-prefixes attribute on a literal result element. The value of both these attributes is a whitespace-separated list of namespace prefixes.

Translating itunes affiliate rss via xslt

I can't get this working for the life of me. Here is a snippet of the xml I get from an RSS feed from itunes affiliate. I want top print the values within tags but I cannot for some reason:
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns:im="http://itunes.apple.com/rss" xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
<id>http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/toppaidapplications/sf=143441/limit=100/genre=6014/xml</id><title>iTunes Store: Top Paid Applications</title><updated>2010-03-24T15:36:42-07:00</updated><link rel="alternate" type="text/html" href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewTop?id=25180&popId=30"/><link rel="self" href="http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/toppaidapplications/sf=143441/limit=100/genre=6014/xml"/><icon>http://phobos.apple.com/favicon.ico</icon><author><name>iTunes Store</name><uri>http://www.apple.com/itunes/</uri></author><rights>Copyright 2008 Apple Inc.</rights>
<entry>
<updated>date</updated>
<id>someID</id>
<title>a</title>
<im:name>b</im:name>
</entry>
<entry>
<updated>date2/updated>
<id>someID2</id>
<title>a2</title>
<im:name>b2</im:name>
</entry>
</feed>
If I try <xsl:apply-templates match="entry"/> it spits out the entire contents of file. If I use <xsl:call-template name="entry"> it will show only one entry and I have to use <xsl:value-of select="//*[local-name(.)='name']"/> to get name but that's a hack. I've used xslt before for xml without namespaces and xml that has proper parent child relationships but not like this RSS feed. Notice entry is not wrapped in entries or anything.
Any help is appreciated. I want to use xslt because I want to alter the itunes link to go through my affiliate account - so something automated wouldn't work for me.
You are matching elements that are in no namespace, but the actual elements in the XML document do belong to a (deafult) namspace: xmlns="http://www.w3.org/2005/Atom".
Therefore, you need to declare the namespace in your stylesheet, let's say xmlns:atom="http://www.w3.org/2005/Atom". and then match not just on {elementName} but on {atom:elementName}, where {elementName} in your case is: "entry".