How to display XSD-validated XML using XSLT

I struggled with this for some time and still could not find a clear answer to this question.

As I understand correctly, I can store data in an XML file, validate it using XSD and then accurately display data using XSLT.

However, I had problems trying to execute XPath queries to select the data that I want to display in my XSLT. When I use generic selectors like ".//" or "*", I get the expected results. However, when I try to use more specific selectors, such as: "root / answers" or any other option, I do not get any results.

The XML file is correctly validated by XSD, so I think my data is at least somewhat correct. When I remove the XSD link in the XML file, effectively deleting the data validation, my XPath requests unexpectedly fire! Is there something I'm missing? I tried adding namespace references to XSLT, but to no avail.

I have described XSD, Sample XL, and Sample XSLT below. Any help or tips would be appreciated!


The XSD defining the structure is as follows. This XSD describes a simple document that contains three elements and applies a constraint; The response code code must be unique.

<?xml version="1.0" encoding="utf-8"?> <xs:schema id="uitext" targetNamespace="http://foo.bar/responsecode.xsd" elementFormDefault="qualified" xmlns:responsecodes="http://foo.bar/responsecode.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="responsecodes:rootType"> <xs:key name="responseCode"> <xs:selector xpath="responsecodes:responses/responsecodes:response"> <xs:annotation> <xs:documentation>All defined responsecodes</xs:documentation> </xs:annotation> </xs:selector> <xs:field xpath="@code"> <xs:annotation> <xs:documentation>Unique responsecode</xs:documentation> </xs:annotation> </xs:field> </xs:key> </xs:element> <xs:complexType name="rootType"> <xs:sequence> <xs:element name="responses" minOccurs="1" maxOccurs="1" type="responsecodes:responseList"> <xs:annotation> <xs:documentation>Defined responsecodes</xs:documentation> </xs:annotation> </xs:element> </xs:sequence> </xs:complexType> <xs:complexType name="responseList"> <xs:sequence> <xs:element name="response" minOccurs="0" maxOccurs="unbounded" type="responsecodes:response"/> </xs:sequence> </xs:complexType> <xs:complexType name="response"> <xs:sequence> <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1"> <xs:annotation> <xs:documentation> Explains the use of the responsecode. </xs:documentation> </xs:annotation> </xs:element> </xs:sequence> <xs:attribute name="code" type="xs:string" use="required"> <xs:annotation> <xs:documentation>Unique code representing the response provided.</xs:documentation> </xs:annotation> </xs:attribute> </xs:complexType> </xs:schema> 

An example XML document may be as follows:

 <?xml version="1.0" encoding="utf-8"?> <?xml-stylesheet type="text/xsl" href="responsecode.xsl"?> <root xmlns="http://foo.bar/responsecode.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://foo.bar/responsecode.xsd responsecode.xsd"> <responses> <response code="firstCode"> <description>Explanation of first code</description> </response> <response code="secondCode"> <description>Explanation of second code</description> </response> <response code="thirdCode"> <description>Explanation of third code.</description> </response> </responses> </root> 

The XSLT test document referred to in the XML file is as follows. (This displays the codes as indicated in a format that will resemble the definitions of the VS2008 enumeration, but aside)

 <?xml version="1.0" encoding="iso-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html><body><h2>Responses</h2> <xsl:for-each select="root/responses/response"> <xsl:choose> <xsl:when test="description != ''"> <br/>'''&lt;description&gt; <br/>'''<xsl:value-of select="description" /> <br/>'''&lt;/description&gt; </xsl:when> </xsl:choose> <br/> <xsl:value-of select="@code" /> </xsl:for-each> </body> </html> </xsl:template> </xsl:stylesheet> 
+6
xml namespaces xpath xslt xsd
source share
3 answers

And, of course, as soon as you submit a question, you yourself will find the answer.

It turned out that there should be a typo in the namespace link. After double checking this message:

xslt-transform-xml-with-namespaces

Which basically turns out to be the same question. (I searched before publishing .... honest!), I again tried to add a link to the namespace, and this time it worked flawlessly!

I have mapped the namespace with the prefix "nsm" (NameSpaceMapping) and voilรก!

 <?xml version="1.0" encoding="iso-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:nsm="http://foo.bar/responsecode.xsd"> <xsl:template match="/"> <html><body><h2>Responses</h2> <xsl:for-each select="nsm:root/nsm:responses/nsm:response"> <xsl:choose> <xsl:when test="nsm:description != ''"> <br/>'''&lt;description&gt; <br/>'''<xsl:value-of select="nsm:description" /> <br/>'''&lt;/description&gt; </xsl:when> </xsl:choose> <br/> <xsl:value-of select="@code" /> </xsl:for-each> </body> </html> </xsl:template> </xsl:stylesheet> 
+6
source share

A simple problem: your XML elements are in a namespace that XSLT knows nothing about.

 <root xmlns="http://foo.bar/responsecode.xsd"> <responses> <!-- ... --> </responses> </root> 

puts your <root> and all descendant elements in the namespace "http://foo.bar/responsecode.xsd" .

Modify your XSL as follows:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:foo="http://foo.bar/responsecode.xsd" exclude-result-prefixes="foo" > <xsl:template match="/"> <html> <body> <h2>Responses</h2> <xsl:for-each select="foo:root/foo:responses/foo:response"> <!-- ... --> </xsl:for-each> </body> </html> </xsl:template> </xsl:stylesheet> 

Notice how the namespace is declared and the prefix is โ€‹โ€‹set. Later, all nodes in this namespace refer to this prefix. exclude-result-prefixes used to ensure that the namespace does not appear in the output unnecessarily.

+8
source share

This is a namespace problem. You will need to add a namespace declaration for http://foo.bar/responsecode.xsd and refer to elements using this namespace. More information can be found here .

So basically you will need something like this:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:test="http://foo.bar/responsecode.xsd"> <xsl:template match="/"> <html> <body> <h2>Responses</h2> <xsl:for-each select="test:root/test:responses/test:response"> <xsl:choose> <xsl:when test="test:description != ''"> <br/>'''&lt;description&gt; <br/>'''<xsl:value-of select="test:description" /> <br/>'''&lt;/description&gt; </xsl:when> </xsl:choose> <br/> <xsl:value-of select="@code" /> </xsl:for-each> </body> </html> </xsl:template> </xsl:stylesheet> 

Note the "xmlns: test" in the xsl:stylesheet attributes. I gave him a test and it works.

+4
source share

All Articles