对于这个问题我有些不知所措。 我正在编写一小段代码,用于根据相应的 XSD 架构验证 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>
也许是因为您的架构未验证?
您的架构中的错误在于 xs:all 元素。
来自W3Schools:
all 元素指定子元素可以以任意顺序出现,并且每个子元素可以出现零次或一次。
但是在您的架构中,您将 xs:all 中的一些元素定义为
maxoccurs="unbounded"
,这是不允许的。例如:
<xs:all>
<xs:element minOccurs="1" maxOccurs="unbounded" ref="transferRoom"/>
<xs:element maxOccurs="unbounded" ref="room"/>
</xs:all>
此处元素“tranferRoom”可以大于1。尝试删除maxoccurrs或替换xs:all。
编辑:
我做了一些测试,当我从 xsd 和 xml 中删除所有命名空间声明(xmlns、目标命名空间等)时,它起作用了。所以我猜命名空间有问题。
我认为你错过了关键点。要纠正,请确保工厂了解名称空间。
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;
}
}