We help IT Professionals succeed at work.

XSLT - XPath to the XSI definition attribute

Molko
Molko used Ask the Experts™
on
I have some xml that I wish to transform, the transformation is dependant upon the

xsi:schemaLocation="http://example/prodv1.xsd http://example/otherstuff.xsd"
or
xsi:schemaLocation="http://example/otherstuff.xsd http://example/prodv2.xsd"

If its prov1 i want to do something, if its prodv2 i do something else. I guess they can come in any order as well

I can write the xpath to pick out all attributes (@*), but I can figure out a way to return a boolean (xpath) that evaulates the existance of http://example/prodv1.xsd



<?xml version="1.0" encoding="UTF-8"?>
<order xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example/prodv1.xsd 
																																																		http://example/prodv2.xsd">
	<items>
		<product>
			<number xsi:type="xs:short">557</number>
			<name>Short-Sleeved Linen Blouse</name>
			<size xsi:nil="true"/>
		</product>
	</items>
</order>

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
not tested but wouldn't it be something like this?

/order[conatins(@xsi:schemaLocation, 'http://example/prodv1.xsd')]

Author

Commented:
Sorry, oops...a typo

I can write the xpath to pick out all attributes (@*), but I cant figure out a way to return a boolean (xpath) that evaulates the existance of http://example/prodv1.xsd
Information Architect
Top Expert 2006
Commented:
Try this as your stylesheet

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     exclude-result-prefixes="xsi"
    version="1.0">
    <xsl:template match="/">
        <xsl:apply-templates select="/*"/>
    </xsl:template>
    
    <xsl:template match="/order[contains(@xsi:schemaLocation, 'http://example/prodv1.xsd')]">
        do one thing here
    </xsl:template>
    
    <xsl:template match="/order[not(contains(@xsi:schemaLocation, 'http://example/prodv1.xsd'))]">
        do other thing here
    </xsl:template>
    
</xsl:stylesheet>

Open in new window

Gertone (Geert Bormans)Information Architect
Top Expert 2006

Commented:
inside the predicate the expression renders to a boolean expression which is false if the returned nodeset is empty

You might be up to a somewhat bigger challenge

I guess they can come in any order as well

seems to imply that you are uncertain about the meaning of schemaLocation

schemaLocation has two components
the part before the space is the targetNamespace of the schema referenced, it is a URI, a resource identifier, which often takes the form of a URL, but it isn't one
the second part (after the white space) is the physical location of the schema, it is a URL and it should point to the actual schema.
Order in an @xsi:schemaLocation is important

For schema that don't have a target namespace there is
@xsi:noNamespaceSchemaLocation
It could be that you also have to test for that

Now the use of schemaLocation implies that the schema you are referring to has a targetNamespace. In that case, chances are that the XML elements defined in that schema are in that namespace. So most often you will find that attribute with an xmlns="..."
In that case the templates will not work, because you can't address the order element in the null namespace if it is in the schema target namespace

So you might have to make the XSLT namespace independent, using local-name(), like this

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     exclude-result-prefixes="xsi"
    version="1.0">
    <xsl:template match="/">
        <xsl:apply-templates select="/*"/>
    </xsl:template>
    
    <xsl:template match="/*[local-name() = 'order'][contains(@xsi:schemaLocation, 'http://example/prodv1.xsd')]">
        do one thing here
    </xsl:template>
    
    <xsl:template match="/*[local-name() = 'order'][not(contains(@xsi:schemaLocation, 'http://example/prodv1.xsd'))]">
        do other thing here
    </xsl:template>
    
</xsl:stylesheet>

Open in new window


In XSLT2 you can simply wildcard match="/*:order" but the above XSLT will work in both

Author

Commented:
Thankyou.
Gertone (Geert Bormans)Information Architect
Top Expert 2006

Commented:
welcome