为什么抛出这个SAXParseException?

时间:2013-08-30 12:03:17

标签: java xml xsd saxparser saxparseexception

我对这个问题有点不知所措。我正在编写一小段代码,它们应该针对相应的XSD Schema验证XML文件。为了测试,我传递了一个有效的XML文件(由Netbeans使用的任何验证)。令我懊恼的是,我收到了以下错误消息:

org.xml.sax.SAXParseException; cvc-elt.1:找不到元素'map'的声明。

这很奇怪,因为Netbeans发现元素'map'的声明就好了。我知道相对文件路径有时可能是个问题,所以我替换了一个绝对路径。结果:同样的问题。

因此,我只能假设SAXParser不使用xsi:schemaLocation属性来确定架构文件。

有谁知道我为什么会出现这种行为?

这是一个SSCCE:

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;


public class ValidatorTest {

    public static void main(String[] args) {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        Document doc = null;
        try {
            DocumentBuilder db = dbf.newDocumentBuilder();
            doc = db.parse(new FileInputStream(new File(args[0])));
        } catch (Throwable ex) {
            ex.printStackTrace();
            System.exit(1);
        }
        SchemaFactory sf = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
        Schema schema = null;
        try {
            schema = sf.newSchema(new StreamSource(new File(args[1])));
        } catch (SAXException ex) {
            ex.printStackTrace();
            System.exit(1);
        }
        Source source = new DOMSource(doc);
        Validator validator = schema.newValidator();
        try {
            validator.validate(source);
            System.out.println("SUCESS!");
        } catch (SAXException ex) {
            ex.printStackTrace();
            System.out.println("FAIL!");
        } catch (IOException ex) {
            ex.printStackTrace();
            System.exit(1);
        }
    }
}

我的XML:

<?xml version="1.0" encoding="UTF-8"?>
<map id="testMap" name="Test Map" xmlns="zorkCloneMapTypes"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="zorkCloneMapTypes /home/max/NetBeanzWorkspace/ZorkClone/src/main/resources/maps/betterMaps.xsd">
    <room id="testingGrounds" name="Testing Grounds" posX="0" posY="1">
        <type>basic</type>
        <description>A dusty arena, enclosed in a circular, wooden fence.  Clearly designed for practicing combat.  There are red blood spatters in the sand.</description>
        <passageNorth>true</passageNorth>
        <passageEast>false</passageEast>
        <passageSouth>false</passageSouth>
        <passageWest>false</passageWest>
        <enemies>
            <enemy>
                <name>Training Master</name>
                <type>Basic</type>
                <description>A Training Master. He will not let you pass until you defeat him in combat.</description>
                <level>1</level>
            </enemy>
        </enemies>
        <containers>
            <container locked="false">
                <name>Equipment locker.</name>
                <description>Equipment locker.</description>
                <level>5</level>
            </container>
            <container locked="false">
                <name>Equipment locker.</name>
                <description>Equipment locker.</description>
                <level>5</level>
            </container>
        </containers>
    </room>
    <transferRoom id="start" name="Starting Map" posX="0" posY="0">
        <type>transfer</type>
        <description>The starting room for the game.</description>
        <transferID>testMap.testingGrounds</transferID>
        <passageNorth>false</passageNorth>
        <passageEast>false</passageEast>
        <passageSouth>true</passageSouth>
        <passageWest>false</passageWest>
        <enemies/>
        <containers/>
    </transferRoom>
</map>

我的XSD:

    <?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="zorkCloneMapTypes"
           targetNamespace="zorkCloneMapTypes"
           elementFormDefault="qualified">
  <xs:element name="map">
    <xs:complexType>
      <xs:sequence>
    <xs:element minOccurs="0" maxOccurs="unbounded" ref="room"/>
    <xs:element minOccurs="1" maxOccurs="unbounded" ref="transferRoom"/>
      </xs:sequence>
      <xs:attribute name="id" type="xs:ID" use="required"/>
      <xs:attribute name="name" type="xs:string" use="required"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="transferRoom">
    <xs:complexType>
      <xs:sequence>
    <xs:element ref="type"/>
    <xs:element ref="description"/>
    <xs:element ref="transferID"/>
    <xs:element ref="passageNorth"/>
    <xs:element ref="passageEast"/>
    <xs:element ref="passageSouth"/>
    <xs:element ref="passageWest"/>
    <xs:element minOccurs="0" maxOccurs="unbounded" ref="enemies"/>
    <xs:element minOccurs="0" maxOccurs="unbounded" ref="containers"/>
      </xs:sequence>
      <xs:attribute name="name" use="required" type="xs:string"/>
      <xs:attribute name="id" use="required" type="xs:ID"/>
      <xs:attribute name="posX" use="required" type="xs:string"/>
      <xs:attribute name="posY" use="required" type="xs:string"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="room">
    <xs:complexType>
      <xs:sequence>
    <xs:element ref="type"/>
    <xs:element ref="description"/>
    <xs:element ref="passageNorth"/>
    <xs:element ref="passageEast"/>
    <xs:element ref="passageSouth"/>
    <xs:element ref="passageWest"/>
    <xs:element minOccurs="0" maxOccurs="unbounded" ref="enemies"/>
    <xs:element minOccurs="0" maxOccurs="unbounded" ref="containers"/>
      </xs:sequence>
      <xs:attribute name="name" use="required" type="xs:string"/>
      <xs:attribute name="id" use="required" type="xs:ID"/>
      <xs:attribute name="posX" use="required" type="xs:string"/>
      <xs:attribute name="posY" use="required" type="xs:string"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="containers">
    <xs:complexType>
      <xs:sequence>
    <xs:element minOccurs="0" maxOccurs="unbounded" ref="container"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="enemies">
    <xs:complexType>
      <xs:sequence>
    <xs:element minOccurs="0" maxOccurs="unbounded" ref="enemy"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="container">
    <xs:complexType>
      <xs:sequence>
    <xs:element ref="name"/>
    <xs:element ref="description"/>
    <xs:element ref="level"/>
      </xs:sequence>
      <xs:attribute name="locked" default="false" type="xs:boolean"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="enemy">
    <xs:complexType>
      <xs:sequence>
    <xs:element ref="name"/>
    <xs:element ref="type"/>
    <xs:element ref="description"/>
    <xs:element ref="level"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="name" type="xs:string"/>
  <xs:element name="type" type="xs:string"/>
  <xs:element name="description" type="xs:string"/>
  <xs:element name="transferID" type="xs:string"/>
  <xs:element name="passageNorth" type="xs:boolean"/>
  <xs:element name="passageEast" type="xs:boolean"/>
  <xs:element name="passageSouth" type="xs:boolean"/>
  <xs:element name="passageWest" type="xs:boolean"/>
  <xs:element name="level" type="xs:int"/>
</xs:schema>

2 个答案:

答案 0 :(得分:0)

可能是因为您的架构没有验证?

架构中的错误位于xs:all元素中。

来自 W3Schools

  

all元素指定子元素可以按任何顺序出现,并且每个子元素可以出现零次或一次。

但是在你的模式中,你在xs中定义了一些元素:all为maxoccurs="unbounded",这是不允许的。 E.G:

<xs:all>
    <xs:element minOccurs="1" maxOccurs="unbounded" ref="transferRoom"/>
    <xs:element maxOccurs="unbounded" ref="room"/>
</xs:all>

此处元素“tranferRoom”可以大于1.尝试删除maxoccurs或替换xs:all。

修改

我做了一些测试,当我从xsd和xml(xmlns,targetnamespace等)中删除所有命名空间声明时,它都有效。所以我猜这个命名空间有问题。

答案 1 :(得分:0)

我认为您缺少关键点。要纠正,请确保工厂知道名称空间。

package xml;

import java.io.File;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

//import com.sun.org.apache.xerces.internal.parsers.DOMParser;
//import com.sun.org.apache.xerces.internal.parsers.DOMParser;

public class SchemaTest {
    public static void main(String args[]) {
         
         String SCHEMA_LANGUAGE_ATTRIBUTE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
         String XSD_SCHEMA_LANGUAGE = "http://www.w3.org/2001/XMLSchema";
        ErrorHandler errorHandler = new SimpleSaxErrorHandler();
        DelegatingEntityResolver entityResolver = new DelegatingEntityResolver();
        
        try {
            String s = "D:/workspace-202006/xml/ns/map.xml" ;
            String s2 ="D:/workspace-202006/xml/ns/fileCopyDemo-binary.xml";
            File file = new File(s);//
//          InputSource inputSource = file. new InputSource("");

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true);
            factory.setValidating(true);
            factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
            
            DocumentBuilder docBuilder = factory.newDocumentBuilder();
            docBuilder.setErrorHandler(errorHandler);
            docBuilder.setEntityResolver(entityResolver);
            docBuilder.parse(file);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class SimpleSaxErrorHandler implements ErrorHandler {

    @Override
    public void warning(org.xml.sax.SAXParseException exception) throws org.xml.sax.SAXException {
        exception.printStackTrace();
    }

    @Override
    public void error(org.xml.sax.SAXParseException exception) throws org.xml.sax.SAXException {
        exception.printStackTrace();
    }

    @Override
    public void fatalError(org.xml.sax.SAXParseException exception) throws org.xml.sax.SAXException {
        // TODO Auto-generated method stub
        
    }
}

class DelegatingEntityResolver implements EntityResolver {

    /** Suffix for DTD files. */
    public static final String DTD_SUFFIX = ".dtd";

    /** Suffix for schema definition files. */
    public static final String XSD_SUFFIX = ".xsd";


    private final EntityResolver dtdResolver;

    private final EntityResolver schemaResolver;


    /**
     * Create a new DelegatingEntityResolver that delegates to
     * the given {@link EntityResolver EntityResolvers}.
     * @param dtdResolver the EntityResolver to resolve DTDs with
     * @param schemaResolver the EntityResolver to resolve XML schemas with
     */
    public DelegatingEntityResolver(EntityResolver dtdResolver, EntityResolver schemaResolver) {
        this.dtdResolver = dtdResolver;
        this.schemaResolver = schemaResolver;
    }
    public DelegatingEntityResolver() {
        this.dtdResolver = null;
        this.schemaResolver = null;
    }


    @Override
    public InputSource resolveEntity(  String publicId, String systemId)
            throws SAXException, IOException {

        if (systemId != null) {
            if (systemId.endsWith(DTD_SUFFIX)) {
                return this.dtdResolver.resolveEntity(publicId, systemId);
            }
            else if (systemId.endsWith(XSD_SUFFIX)) {
                return this.schemaResolver.resolveEntity(publicId, systemId);
            }
        }

        // Fall back to the parser's default behavior.
        return null;
    }


    @Override
    public String toString() {
        return "EntityResolver delegating " + XSD_SUFFIX + " to " + this.schemaResolver +
                " and " + DTD_SUFFIX + " to " + this.dtdResolver;
    }

}