XSL Create Element Which Has Colon in Name - xslt

This works fine
<xsl:element name="title">
<xsl:value-of select="#title"/>
</xsl:element>
However this doesn't
<xsl:element name="image:title">
<xsl:value-of select="#title"/>
</xsl:element>
Please can someone advise? When I say it doesn't work, the page breaks. Unfortunately due to the nature of the system, I can't see an error
The top of the page reads as follows
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:udf="http://www.virtualfestivals.com/udf">
<xsl:output method="html" omit-xml-declaration="no" />

The error you are getting is probably along the lines of Undeclared namespace prefix {image}. The "image" part of you element name is actually a "namespace prefix", just like how all the xslt elements are prefixed with "xsl:".
To resolve this, you need to add a declaration for the "image" prefix somewhere in your XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:image="my:image"
xmlns:udf="http://www.virtualfestivals.com/udf">
Of course, what the URI is for your "image" depends on what you are need to add the prefix for in the first place. (EDIT: As per your comment, you will need to set it to http://www.google.com/schemas/sitemap-image/1.1)
Note that you don't actually need to use xsl:element here. If the element name is static, just write out the element like so...
<image:title>
<xsl:value-of select="#title"/>
</image:title>
Read up on namespaces at http://www.xml.com/pub/a/2001/04/04/trxml/ for example.

Related

exsl:document - trying to generate output file

I have this code so far: - now updated with different code
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl"
exclude-result-prefixes="exsl"
version="1.0">
<xsl:output method="xml"/>
<xsl:variable name="emailPID" select="attr[#tag='00100020']"/>
<xsl:variable name="emailPName" select="attr[#tag='00100010']"/>
<!-- overwritten by application with actual values -->
<xsl:param name="calling" select="'SAMPLE_MOD'"/>
<xsl:param name="called" select="'SERVER1'"/>
<xsl:param name="date" select="'20051206'"/>
<xsl:param name="time" select="'115600.000'"/>
<xsl:template match="/dataset">
<exsl:document href="file:///c|/apps/foo.txt">
<xsl:copy-of select="$emailPID"/>
<xsl:copy-of select="$emailPName"/>
</exsl:document>
</xsl:template>
</xsl:stylesheet>
The transformer doesn't throw any errors that I see, but I cannot see the "c:\apps\foo.txt" file I am expecting either. Is there some formatting wrong here or am I leaving something out?
thank you for looking
The processor should throw an error when it sees
extension-element-prefixes="exslt"
because the prefix "exslt" has not been declared. Perhaps you meant "exsl". At present, "exsl" is not declared as an extension namespace, therefore "exsl:document" is a simple literal result element rather than an instruction.
The href attribute of an exsl:document needs to be a valid URI. The XSLT engine is probably confusing the part before the colon (i.e. c) as a URI scheme, not part of the path.
If you are using an absolute address for the filesystem, include the file: URI scheme:
<exsl:document href="file:///c:\apps\foo.txt">
The drive colon ad slashes may cause problems on non-windows platforms so you can instead try:
<exsl:document href="file:///c|/apps/foo.txt">

Type of Amazon xml response breaks php xsl

Since Amazon shut off it's xslt support, I wanted to move it to my own server using php5's xsl. My output needs to be in a text format for my JS to process it for a web page. My problem is Amazon's xml response (very abbreviated) looks like this
<?xml version="1.0" ?>
<ItemLookupResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2011-08-01">
/............./
</ItemLookupResponse>
My problem is that my xsl stylesheet works fine as long as I remove the xmlns="http://...". What is needed in a xsl style to have it bypass or just ignore that ?
All the nodes I need are well inside that outer one.
Here is the xslt:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="CallBack" select="'amzJSONCallback'"/>
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:value-of select="$CallBack"/>
<xsl:text>( { "Item" : </xsl:text><xsl:apply-templates/><xsl:text> } ) </xsl:text>
</xsl:template>
<xsl:template match="OperationRequest"></xsl:template>
<xsl:template match="Request"></xsl:template>
<xsl:template match="Items">
<xsl:apply-templates select="Item"/>
</xsl:template>
<xsl:template match="Item">
<xsl:text> {</xsl:text>
<xsl:text>"title":"</xsl:text><xsl:apply-templates select="ItemAttributes/Title"/><xsl:text>",</xsl:text>
<xsl:text>"author":"</xsl:text><xsl:apply-templates select="ItemAttributes/Author"/><xsl:text>",</xsl:text>
<xsl:text>"pubbdate":"</xsl:text><xsl:apply-templates select="ItemAttributes/PublicationDate"/><xsl:text>"</xsl:text>
<xsl:text>} </xsl:text>
</xsl:template>
</xsl:stylesheet>
You should probably learn how XML namespaces work. In a nutshell, you have to define a namespace prefix in your XSL file like this:
<xsl:stylesheet ... xmlns:awse="http://webservices.amazon.com/AWSECommerceService/2011-08-01">
Then, you have to use qualified names to match and select elements under that namespace:
<xsl:template match="awse:ItemLookupResponse">
(With XSLT 2.0, you can define a default namespace. But since you're using PHP, you're probably limited to XSLT 1.0.)
It looks like nwellnhof is correct. I was using the wrong namespace in my testing. All I did was add:
<xsl:stylesheet ... xmlns:aws="http://webservices.amazon.com/AWSECommerceService/2011-08-01">
Then the elements look like
<xsl:template match="aws:ItemLookupResponse">
Now the conversion works perfectly. I don't know why it didn't work the first time I tried it.

XSL namespaces and nested xsl:for-each

I have below XML and would like to iterate through the element as such the i could display it in some format like:
PIN 1<br/>
XYZ<br/>
HELLO<br/>
PIN 2<br/>
ABC<br/>
HI<br/>
XML:
<RootResponse xmlns:ip="urn:domain:tx:inPayment" xmlns:ipn="urn:domain:tx:Pin">
<OutBoundMessage>
<ip:InfoMessage>
<ipn:Alert>PIN 1</ipn:Alert>
<ipn:Code>
<ip:CodeLabel>XYZ</ip:CodeLabel>
<ip:CodeMessage>HELLO</ip:CodeMessage>
</ipn:Code>
</ip:InfoMessage>
<ip:InfoMessage>
<ipn:Code>
<ipn:Alert>PIN 2</ipn:Alert>
<ip:CodeLabel>ABC</ip:CodeLabel>
<ip:CodeMessage>HI</ip:CodeMessage>
</ipn:Code>
</ip:InfoMessage>
</OutBoundMessage>
</RootResponse>
I Can't seem to find a solution. Any suggestion?
I would recommend following the W3C schools XSLT tutorial, this should give you all you need to solve this relatively simple XSLT problem.
You are right that you will have to pay attention to namespaces, although again this is quite straightforward. Simply ensure that your XSLT defines the namespaces required, and that you prefix element names in your XPath statements accordingly. See the following:
XML Namespaces and How They Affect XPath and XSLT
You should declare the namespaces in your XSLT and then use the declared prefix in your expressions.
Below is an example of how to do that, using templates(i.e. "push style") rather than xsl:for-each (e.g. "pull style").
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ip="urn:domain:tx:inPayment"
xmlns:ipn="urn:domain:tx:Pin"
exclude-result-prefixes="ip ipn">
<xsl:output indent="yes" />
<xsl:template match="ipn:Alert">
<xsl:text>
</xsl:text>
<xsl:apply-templates />
<br/>
</xsl:template>
<xsl:template match="ip:*[starts-with(local-name(),'Code')]">
<xsl:text>
  </xsl:text>
<xsl:apply-templates/>
<br/>
</xsl:template>
</xsl:stylesheet>

Using functions in XSLT

I'm learning XSLT. These questions may be obvious, but I'm really stuck now.
Oxygen returns the following two kind of errors:
Namespace is not declared for 'ownFunction()'. ("undeclared namespace prefix {xs}")
unknown system function index-of-string() The XSLT function index-of-string I got from this website doesn't seems to be recognized
This is a simplified version of the XSL file:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xmlns:foo="http://www.wathever.com">
<xsl:output method="xml" />
<xsl:function name="foo:ownFunction" as="xs:string">
<xsl:param name="string" as="xs:string"/>
<xsl:choose>
<xsl:when test='contains($string,"src=")'>
<xsl:variable name="position"><xsl:value-of select="index-of-string($string,'src=')"/>+<xsl:number value="10"/></xsl:variable>
<xsl:variable name="partString"><xsl:value-of select="substring($string,$position)"/></xsl:variable>
<xsl:variable name="length"><xsl:value-of select="index-of-string($partString,'quot;')"/> - <xsl:number value="2"/></xsl:variable>
<xsl:value-of select="substring($partString,1,$length)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="hotpot-jmatch-file/data/title"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<xsl:template match="/">
<data>
<title>
<xsl:variable name="string"><xsl:value-of select="hotpot-jmatch-file/data/title"/></xsl:variable>
<xsl:value-of select="foo:ownFunction($string)"/>
</title>
</data>
</xsl:template>
</xsl:stylesheet>
Oxygen returns the following two kind
of errors:
1) Namespace is not declared for
'ownFunction()'. ("undeclared
namespace prefix {xs}")
This is actually an XML issue. Any XSLT stylesheet myst be a well-formed XML document. Among other requirements for well-formedness, any namespace prefix used must be bound to a namespace URI in a namespace declaration.
To correct this bind the "xs" prefix to "http://www.w3.org/2001/XMLSchema" -- this means to add xmlns:xs="http://www.w3.org/2001/XMLSchema" to an element (usually the top element is a good choice for this namespace.
You have the same problem with "foo:ownFunction". You must have the prefix "foo" bound/defined and visible, before using it. Just add xmlns:foo="my:foo" to the top element of your stylesheet.
2) "unknown system function
index-of-string()". The XSLT function
"index-of-string" I got from this
website doesn't seems to be
recognized:
http://www.xsltfunctions.com/xsl/functx_index-of-string.html
You have forgotten to either copy and paste the function from Priscilla Walmsley's site or to save it in a separate file (recommended) and then use <xsl:import> or <xsl:include> to import/include this stylesheet file to your transformation.
Finally, such issues show that you need a more systematic introduction of XSLT. Get a good book and read it well. You won't be sorry. This answer may be useful in listing what I consider good XSLT and XPath learning resources.
Use
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xmlns:foo="http://www.wathever.com"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs functx""
xmlns:functx="http://www.functx.com">
<xsl:import href="location-of-functx-library.xsl"/>
...
<xsl:value-of select="functx:index-of-string($partString,'quot;')"/>
That samples defines the schema namespace and binds it to the prefix xs, defines the namespace of the function library you linked to. You will also need to download the function library implementation and import it as shown.

XPath: Selecting nodes included by an <xsl:include>

There's an XSL that includes another XSL:
<xsl:include href="registered.xsl"/>
That included file has a list of nodes:
<g:registered>
<node1/>
<node2/>
</g:registered>
Documentation says that "the children of the <xsl:stylesheet> element in this document replace the element in the including document", so I would think that, given the include directive has worked, I can select g:registered nodes like if they always belonged to the inluding document:
select="document('')/xsi:schema/g:registered"
That returns an empty nodeset though.
However, this:
select="document('registered.xsl')/xsi:schema/g:registered"
does select what is required, but that, as I suppose, means opening the included file for the second time which doesn't seem nice to me.
So how do I select those includes without opening the file second time?
EDIT
Requested document structure:
Included document:
<?xml version='1.0' encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:g="http://www.sample.com/ns">
<g:registered-templates>
<SampleTemplate/>
<WrongTemplate/>
</g:registered-templates>
<xsl:include href="Sample Template.xsl" />
<xsl:include href="Wrong Template.xsl" />
</xsl:stylesheet>
Including document:
<?xml version='1.0' encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:g="http://www.sample.com/ns">
<xsl:output method="text"/>
<xsl:include href="Label Registration.xsl"/>
<!-- How do I refer to just loaded inclusion without directing engine to the file again? -->
<xsl:variable name="template-names" select="document('Label Registration.xsl')/xsl:stylesheet/g:registered-templates"/>
<xsl:template match="Job">
<xsl:for-each select="WorkItem">
<xsl:apply-templates select="$template-names/*[local-name()=current()/#name]">
<xsl:with-param name="context" select="." />
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Selecting into your variable template-names queries the transformation source document - not your included stylesheet.
If you want to refer to g:registered-templates you have to point to the file like a second source document.
EDIT
I'm not really sure. but it looks like you want to create an element according to the attribute value.
In that case this post will be interesting for you.
<xsl:for-each select="WorkItem">
<xsl:element name="{Type}" >
<xsl:value-of select="current()/#name"/>
</xsl:element>
</xsl:for-each>
Ok, my understanding was wrong.
The document('') function opens the file anyway, so it has no advantages, performance-wise, over document('registered.xsl'). And since it queries the file, not the now-modified DOM model of current document, the result does not include my includes.
And it is not possible to query DOM model of the transformation template itself, as far as I'm concerned.