-->

How to reuse elements from another Schema / Namesp

2019-03-01 12:32发布

问题:

I'm trying to define a Schema which allows the use of specific (X)HTML elements in certain places. The problem that I'm facing is that the Schema fails compiling.

Here's the Schema:

<?xml version="1.0"?>
<xs:schema
    xmlns:html="http://www.w3.org/1999/xhtml"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>

    <xs:import
        namespace="http://www.w3.org/1999/xhtml"
        schemaLocation="http://www.w3.org/MarkUp/Schema/xhtml11.xsd"
    />

    <xs:element name="foo">
        <xs:complexType>
            <xs:sequence>
                <xs:element
                    ref="html:blockquote"
                    minOccurs="0"
                    maxOccurs="unbounded"
                />
            </xs:sequence>
        </xs:complexType>
    </xs:element>

</xs:schema>

That's the XML file:

<foo xmlns:html="http://www.w3.org/1999/xhtml">
    <html:blockquote>The quick brown fox jumped over the lazy dog.</html:blockquote>
</foo>

That's the error message that I get:

christian@armor01:~/testCase$ xmllint -schema foo.xsd -noout foo.xml
foo.xsd:12: element element: Schemas parser error : Element \
'{http://www.w3.org/2001/XMLSchema}element', attribute 'ref': The QName value \
'{http://www.w3.org/1999/xhtml}blockquote' does not resolve to a(n) element \
declaration.
WXS schema foo.xsd failed to compile

I understand what the error message means, but I do not understand why the error happens. The error message means that when I refer to blockquote, it cannot find blockquote. But I do not understand why this error happens since I'm importing the XHTML 1.1 schema.

I also tried to find out whether this is a problem specific to xmllint. So I wrote a little Java program to perform the Schema validation, but I'm basically getting the same error.

Here's the Java program:

import java.io.*;
import java.net.*;
import javax.xml.*;
import javax.xml.parsers.*;
import javax.xml.validation.*;
import org.w3c.dom.*;

public class Validate {
    public static void main(final String... args) throws Exception {
        final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        //dbf.setValidating(true);
        dbf.setSchema(schemaFactory.newSchema(new File(args[0]).toURI().toURL()));
        final DocumentBuilder db = dbf.newDocumentBuilder();
        final Document doc = db.parse(args[1]);
    }
}

Here's the error I'm getting from that program:

christian@armor01:~/testCase$ java Validate foo.xsd foo.xml
Exception in thread "main" org.xml.sax.SAXParseException; \
systemId: file:/home/christian/testCase/foo.xsd; \
lineNumber: 12; \
columnNumber: 88; \
src-resolve: Cannot resolve the name 'html:blockquote' to a(n) 'element declaration' component.

So clearly, I am doing something wrong in the Schema - but what? What is the correct way to define a Schema (for a target syntax without namespace) that reuses elements from another Schema/Namespace like XHTML?

BTW I also tried <xs:include/> but that seemed inappropriate to me, and it failed because it requires that the including schema and the included schema target the same namespace.

回答1:

It seems that the "blockquote" element is not defined as global element, thus you can not refer to it directly. If you have a look in the sub part of the xhtml schema http://www.w3.org/MarkUp/SCHEMA/xhtml11-model-1.xsd, you can notice that its type is xhtml.blockquote.type.

So a workaround would be to declare your blockquote like so :

<xs:schema xmlns:html="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:import namespace="http://www.w3.org/1999/xhtml" schemaLocation="http://www.w3.org/MarkUp/Schema/xhtml11.xsd"/>
        <xs:element name="foo">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="blockquote" type="html:xhtml.blockquote.type" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

along with this valid XML instance:

<?xml version="1.0"?>
<foo xmlns:html="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test.xsd">
    <blockquote><html:p>quick brown fox jumped over the lazy dog.</html:p></blockquote>
</foo>

You will notice that the blockquote element is not bound to the html namespace. Since you import other namespace's elements, I think also it would be a better practice to set a default target namespace to your own elements.