1

I'm transforming an XML Schema using XSLT 2.0. The first schema (s1.xsd) imports a second schema (s2.xsd) as follows:

Content of s1.xsd

<schema xmlns="http://www.w3.org/2001/XMLSchema" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema.xsd"
    xmlns:ns1="URI1" targetNamespace="URI2" 
    elementFormDefault="qualified" attributeFormDefault="unqualified">
    <import namespace="URI1" schemaLocation="s2.xsd"/>
    <element name="element1"/>
    <element name="element2"/>
</schema>

and content of s2.xsd

<schema xmlns="http://www.w3.org/2001/XMLSchema"
    xmlns:ns1="URI1" targetNamespace="URI1">
    <attribute name="attr1"/>
<schema>

My XSLT declares the XS namespace as follows:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">  

I would like to merge the nodes of s2.xsd into the <schema>-element of s1.xsd. So far, I've tried

<xsl:template name="merge_imported_schemas">
    <xsl:for-each select="/schema/import[@namespace = //namespace::*]">
        <!-- file exists? -->
        <xsl:choose>
            <xsl:when test="boolean(document(@schemaLocation))">
                <!-- schema found -->
                <xsl:copy-of select="document(@schemaLocation)/*/node()"/>
            </xsl:when>
            <xsl:otherwise>
                <!-- schema not found -->
                <xsl:message terminate="yes">
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each>
</xsl:template>

but I don't get the desired result. Could anyone please tell me what I'm doing wrong? I suspect there is a namespace-collision here, but honestly I find using namespaces a little confusing. Thanks!

conciliator
  • 6,078
  • 6
  • 41
  • 66
  • What I really wanted, was to append the content of s2.xsd to s1.xsd, and then parse s1.xsd as a single file. To the best of my knowledge, this is not possible, but a work-around involves using a temporary result tree (see e.g. http://www.xml.com/pub/a/2003/12/03/tr.html). To achieve this, the call seems to do the trick. – conciliator May 20 '10 at 14:14

1 Answers1

2

You need to qualify the elements in your XPath. At the moment select="/schema/import[@namespace = //namespace::*]"> doesn't match anything at all, because there is no element /schema. The XPath is trying to match elements with no namespace.

Change it to select="/xs:schema/xs:import[@namespace = //namespace::*]"> and it should work.

Remember, namespace prefixes are an alias for the namespace URI, and if you have a default namespace (as in your xsd files), elements with no prefix are still namespace-qualified.

As an aside, instead of <xsl:for-each select="/schema/import[@namespace = //namespace::*]">, you might have more success using <xsl:apply-templates select="/xs:schema/node()", and defining different templates for the different kinds of node that you wish to copy into the output tree.

Paul Butcher
  • 6,902
  • 28
  • 39
  • Thanks Paul, I forgot. :) Having augmented my XPath query with the correct namespace prefixes, I decided to try to count the number of nodes. Like this: Before: After: Unfortunately, they both give me the same number (44; which incidently is only 2 more than the answer to everything). – conciliator May 20 '10 at 13:01
  • From the information given, it looks like you might be discarding the elements from the original schema. – Paul Butcher May 20 '10 at 13:06
  • Well, that could be it. However, I changed the with (counting the number of elements right below /schema in s2.xsd). It says 22... I'm kind'a lost. – conciliator May 20 '10 at 13:17
  • `copy-of` was most likely correct, but as far as I can see, you are only copying elements from the imported document into the output document, and not copying any elements from the source document. – Paul Butcher May 20 '10 at 13:41
  • I think, sir, that you are absolutely right. I've misunderstood the effect of copy-of. (+1) – conciliator May 20 '10 at 13:50