A: 

Not sure what you're looking for here. XSLT will copy from the source doc to the destination doc however you tell it to. For example:

<sch:fooOut>
  <sch:bar>
    <xsl:copy>
      <sch1:attr1>
      <sch1:attr2>
    </xsl:copy>
  </sch:bar>
</sch:fooOut>

What kind of validation are you looking for? You may be better off using something other than XSLT if you're looking for a more dynamic solution.

John Norcott
What I'm trying to say is that I want to sort a bunch of elements, they're either one type or another. If they're one type, they should go in one section of the output, and if they're the other, they should go in another section. The schema is what says what goes where. Does that make more sense?
adam_0
+2  A: 

Schema ("schema.xs"):

<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.whatever.com/schema"&gt;
    <element name="fooOut">
        <complexType name="fooOut">
            <sequence>
                <element name="bar">
                    <complexType>
                        <sequence>
                            <element name="attr1" type="sch:myBarType" minOccurs="0" maxOccurs="unbounded"/>
                            <element name="attr2" type="sch:myBarType" minOccurs="0" maxOccurs="unbounded"/>
                        </sequence>
                    </complexType>
                </element>
                <element name="stuff">
                    <complexType>
                        <sequence>
                            <element name="attr3" type="sch:myStuffType" minOccurs="0" maxOccurs="unbounded"/>
                            <element name="attr4" type="sch:myStuffType" minOccurs="0" maxOccurs="unbounded"/>
                        </sequence>
                    </complexType>
                </element>
            </sequence>
        </complexType>
    </element>
</schema>

Input:

<sch:foo xmlns:sch="http://www.whatever.com/schema"&gt;   
    <sch:attr1>val1</sch:attr1>   
    <sch:attr2>val2</sch:attr2>   
    <sch:attr3>val3</sch:attr3>   
    <sch:attr4>val4</sch:attr4>   
</sch:foo> 

Stylesheet:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:sch="http://www.whatever.com/schema"&gt;
    <xsl:param name="schema-name" select="'schema.xs'"/>
    <xsl:variable name="input" select="/"/>
    <xsl:template match="/">
        <xsl:apply-templates select="document($schema-name)/node()"/>
    </xsl:template>
    <xsl:template match="xs:element[xs:complexType]">
        <xsl:element name="{@name}" namespace="http://www.whatever.com/schema"&gt;
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
    <xsl:template match="xs:element[not(xs:complexType)]">
        <xsl:element name="{@name}" namespace="http://www.whatever.com/schema"&gt;
            <xsl:value-of select="$input/*/sch:*[name()=current()/@name or
                                        substring-after(name(),':')=current()/@name]"/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Result:

<?xml version="1.0" encoding="UTF-16"?>
<fooOut xmlns="http://www.whatever.com/schema"&gt;
    <bar>
        <attr1>val1</attr1>
        <attr2>val2</attr2>
    </bar>
    <stuff>
        <attr3>val3</attr3>
        <attr4>val4</attr4>
    </stuff>
</fooOut>

Note: This is an XSLT 1.0 solution, but I think this can be done better with XSLT 2.0.- Also, if the schema is a more proper one (elements definitions and types definitions) this method could work with keys. Another method (input driven and not schema driven), despite being more complex, also could be done but I'm runnig out of time.

Edit: Now, suppose these schemas

schemaA.xsd

<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.whatever.com/schema"&gt;
    <include schemaLocation="schemaB.xsd"/>
    <element name="fooOut" type="fooOut"/>
    <complexType name="fooOut">
        <element name="anotherGroup" type="anotherGroup" minOccurs="0" maxOccurs="unbounded"/>
    </complexType>
    <complexType name="anotherGroup">
        <sequence>
            <element name="name" type="xs:string" minOccurs="1" maxOccurs="1" />
            <element name="bar" type="barListType" minOccurs="0" maxOccurs="1" />
            <element name="stuff" type="stuffListType" minOccurs="0" maxOccurs="1" />
        </sequence>
    </complexType>
</schema>

schemaB.xsd

<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.whatever.com/schema"&gt;
    <include schemaLocation="schemaC.xsd"/>
    <complexType name="barListType">
        <group ref="barGroup" maxOccurs="unbounded" />
    </complexType>
    <complexType name="stuffListType">
        <group ref="stuffGroup" maxOccurs="unbounded" />
    </complexType>
</schema>

schemaC.xsd

<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.whatever.com/schema"&gt;
    <group name="barGroup">
        <choice>
            <element name="attr1" type="blah1" minOccurs="0" maxOccurs="1" />
            <element name="attr2" type="blah2" minOccurs="0" maxOccurs="1" />
            <!-- etc -->
        </choice>
    </group>
    <group name ="stuffGroup">
        <choice>
            <element name="attr3" type="blah3" minOccurs="0" maxOccurs="1" />
            <element name="attr4" type="blah4" minOccurs="0" maxOccurs="1" />
            <!-- etc -->
        </choice>
    </group>
</schema>

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt;
    <xsl:output method="xml" encoding="UTF-8" />
    <xsl:param name="schema-name" select="'schemaA.xsd'" />
    <xsl:variable name="input" select="/*/*/*" />
    <xsl:variable name="root" select="document($schema-name)/*/xs:element[not(..//xs:element/@ref = @name)]" />
    <xsl:variable name="uri" select="$root/../@targetNamespace" />
    <xsl:template match="/" name="root">
        <xsl:param name="schema" select="$root/../*"/>
        <xsl:choose>
            <xsl:when test="$schema[self::xs:include]">
                <xsl:call-template name="root">
                    <xsl:with-param name="schema" select="$schema[not(self::xs:include)]|document($schema[self::xs:include]/@schemaLocation)/*/*"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:apply-templates select="$root">
                    <xsl:with-param name="schema" select="$schema"/>
                    <xsl:with-param name="input" select="$input"/>
                </xsl:apply-templates>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <xsl:template match="xs:element">
        <xsl:param name="schema"/>
        <xsl:param name="input"/>
        <xsl:variable name="complex" select="xs:complexType|
                                             $schema[self::xs:complexType][@name=current()/@type]"/>
        <xsl:element name="{@name|@ref}" namespace="{$uri}">
            <xsl:choose>
                <xsl:when test="$complex">
                    <xsl:apply-templates select="$complex">
                        <xsl:with-param name="schema" select="$schema"/>
                        <xsl:with-param name="input" select="$input"/>
                    </xsl:apply-templates>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="$input[local-name()=current()/@name and
                                  namespace-uri()=$uri]"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:element>
    </xsl:template>
    <xsl:template match="xs:group[@ref]">
        <xsl:param name="schema"/>
        <xsl:param name="input"/>
        <xsl:apply-templates select="$schema[self::xs:group][@name=current()/@ref]">
            <xsl:with-param name="schema" select="$schema"/>
            <xsl:with-param name="input" select="$input"/>
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="xs:element[@name='name']" priority="1">
        <xsl:element name="{@name}" namespace="{$uri}">foobar</xsl:element>
    </xsl:template>
    <xsl:template match="xs:element[@maxOccurs='unbounded']">
        <xsl:param name="schema"/>
        <xsl:param name="input"/>
        <xsl:variable name="current" select="."/>
        <xsl:for-each select="$input">
            <xsl:element name="{$current/@name}" namespace="{$uri}">
                <xsl:apply-templates select="$schema[self::xs:complexType][@name=$current/@type]">
                    <xsl:with-param name="schema" select="$schema"/>
                    <xsl:with-param name="input" select="./*"/>
                </xsl:apply-templates>
            </xsl:element>
        </xsl:for-each>
    </xsl:template>
    <xsl:template match="*">
        <xsl:param name="schema"/>
        <xsl:param name="input"/>
        <xsl:apply-templates>
            <xsl:with-param name="schema" select="$schema"/>
            <xsl:with-param name="input" select="$input"/>
        </xsl:apply-templates>
    </xsl:template>
</xsl:stylesheet>

Result:

<fooOut xmlns="http://www.whatever.com/schema"&gt;
    <anotherGroup>
        <name>foobar</name>
        <bar>
            <attr1>val1</attr1>
            <attr2>val2</attr2>
        </bar>
        <stuff>
            <attr3>val3</attr3>
            <attr4>val4</attr4>
        </stuff>
    </anotherGroup>
    <anotherGroup>
        <name>foobar</name>
        <bar>
            <attr1>val5</attr1>
            <attr2>val6</attr2>
        </bar>
        <stuff>
            <attr3>val7</attr3>
            <attr4>val8</attr4>
        </stuff>
    </anotherGroup>
</fooOut>

Note: This works but your second questions (or problem) shows that there is no general case stylesheet. Why? Because with XSLT you must bind an input (with well known schema) to an output (with well known schema too). So this specific stylesheet could do the job:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:sch="http://www.whatever.com/schema"&gt;
    <xsl:output method="xml" encoding="UTF-8" />
    <xsl:param name="schema-name" select="'schemaC.xsd'" />
    <xsl:template match="sch:foo">
        <sch:fooOut>
            <xsl:apply-templates/>
        </sch:fooOut>
    </xsl:template>
    <xsl:template match="sch:myGroup">
        <sch:anotherGroup>
            <sch:name>foobar</sch:name>
            <sch:bar>
                <xsl:copy-of select="*[local-name()=document($schema-name)/*/*[@name='barGroup']//@name]" />
            </sch:bar>
            <sch:stuff>
                <xsl:copy-of select="*[local-name()=document($schema-name)/*/*[@name='stuffGroup']//@name]" />
            </sch:stuff>
        </sch:anotherGroup>
    </xsl:template>
</xsl:stylesheet>

Result:

<sch:fooOut xmlns:sch="http://www.whatever.com/schema"&gt;
    <sch:anotherGroup>
        <sch:name>foobar</sch:name>
        <sch:bar>
            <sch:attr1>val1</sch:attr1>
            <sch:attr2>val2</sch:attr2>
        </sch:bar>
        <sch:stuff>
            <sch:attr3>val3</sch:attr3>
            <sch:attr4>val4</sch:attr4>
        </sch:stuff>
    </sch:anotherGroup>
    <sch:anotherGroup>
        <sch:name>foobar</sch:name>
        <sch:bar>
            <sch:attr1>val5</sch:attr1>
            <sch:attr2>val6</sch:attr2>
        </sch:bar>
        <sch:stuff>
            <sch:attr3>val7</sch:attr3>
            <sch:attr4>val8</sch:attr4>
        </sch:stuff>
    </sch:anotherGroup>
</sch:fooOut>
Alejandro
That solution does look pretty tricky, and I'm willing to wait if you can show me later. In the stylesheet, what would I put in for `schema-name`?I'll try to get this solution working but if it's easier to use XSLT 2.0, that would be much preferred.
adam_0
@adam_0: `schema-name` param is just the schema document name. This is tricky but not because the method (I've driven the transformation with the schema and used data to populate). This is tricky because the schema is not modular. If it will be modular, I should need an entry point element (root element) and navegate the schema across types definitions (That would be easier with keys)
Alejandro
Could you please clarify what you mean by "modular"?
adam_0
While I can get your example to run, I'm having trouble implementing it in the real situation. In my case, the XML elements that I need to sort are 4 or 5 layers deep in both the input and output documents. How difficult would it be to modify your example to work in that case?In addition to this, I think that I may be making this too hard for myself - I'm manually generating the rest of the XML document. Would it be possible to make the XSLT document so that the layers that I'm generating by hand are automatically created?
adam_0
Sorry for adding all these comments, but I noticed that the tags in the output are without the namespace. My output definitely needs the namespace on every element tag or else it won't work properly. How would you add that in?
adam_0
I'm also having trouble understanding exactly how your example works... could you please explain what it does (in particular those last two templates are confusing me)?
adam_0
Wow! This new code is quite amazing and I can really understand it! I'm having trouble implementing it due to a complication that I left out, but I'll add that in again and make things worth your while.
adam_0