我使用Java的JAXB解析器将XML文件编组和解组到特定的类。解组工作正常,然而,它在编组文件时会出现以下错误:
cvc-complex-type.2.4.a:从元素' DataPath'开始发现无效内容。其中一个{" http://hg.flyingwhales.nl/cinnabar/schemas/project.xsd":DataPath}'是预期的。
我不明白为什么这不起作用,因为解密文件工作正常。
根据要求,这是一个MCVE:
ProjectRepository.java:
package com.flyingwhales;
import org.xml.sax.SAXException;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.File;
import java.io.IOException;
/**
* Created by Jesse on 11/13/2016.
*/
public final class ProjectRepository {
private static Validator validator;
private static Marshaller marshaller;
private static Unmarshaller unmarshaller;
// This class is not meant to be instantiated.
private ProjectRepository() {}
static {
File schemaFile = new File("project.xsd");
SchemaFactory schemaFactory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
try {
Schema schema = schemaFactory.newSchema(schemaFile);
validator = schema.newValidator();
// Initialize JAXB stuff too.
JAXBContext jaxbContext = JAXBContext.newInstance(Project.class);
marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setSchema(schema);
unmarshaller = jaxbContext.createUnmarshaller();
} catch (SAXException | JAXBException e) {
e.printStackTrace();
}
}
public static Project load(File file) throws Exception {
if (!validate(file)) {
throw new Exception("project file contains invalid markup");
}
Project project = (Project)unmarshaller.unmarshal(file);
project.setProjectFile(file);
return project;
}
public static void save(Project project, File path) throws JAXBException {
marshaller.marshal(project, path);
}
public static boolean validate(File file) throws IOException {
Source source = new StreamSource(file);
try {
validator.validate(source);
} catch (SAXException e) {
return false;
}
return true;
}
}
Project.java
package com.flyingwhales;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.File;
@XmlRootElement(name = "Project")
public class Project {
private String name = "Project";
private String type = "Standalone";
private String dataPath = "Data";
private String scriptPath = "Data/Scripts";
private String artPath = "Art";
private String sfxPath = "Sound/SFX";
private String bgmPath = "Sound/BGM";
private File projectFile;
public Project() { }
public Project(File file) {
setProjectFile(file);
}
@XmlAttribute( name = "name" )
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlAttribute (name = "type" )
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@XmlElement(name = "DataPath")
public String getDataPath() {
return dataPath;
}
public void setDataPath(String dataPath) {
this.dataPath = dataPath;
}
@XmlElement (name = "ScriptPath")
public String getScriptPath() {
return scriptPath;
}
public void setScriptPath(String scriptPath) {
this.scriptPath = scriptPath;
}
@XmlElement (name = "ArtPath")
public String getArtPath() {
return artPath;
}
public void setArtPath(String artPath) {
this.artPath = artPath;
}
@XmlElement (name = "SFXPath")
public String getSfxPath() {
return sfxPath;
}
public void setSfxPath(String sfxPath) {
this.sfxPath = sfxPath;
}
@XmlElement (name = "BGMPath")
public String getBgmPath() {
return bgmPath;
}
public void setBgmPath(String bgmPath) {
this.bgmPath = bgmPath;
}
void setProjectFile(File file) {
projectFile = file;
}
public File getProjectFile() {
return projectFile;
}
}
package-info.java
@XmlSchema(namespace = "http://hg.flyingwhales.nl/cinnabar/schemas/project.xsd")
package com.flyingwhales;
import javax.xml.bind.annotation.XmlSchema;
Main.java
package com.flyingwhales;
import javax.xml.bind.JAXBException;
import java.io.File;
public class Main {
public static void main(String[] args) {
// Open and parse a file from the filesystem.
try {
Project loadedProject = ProjectRepository.load(new File("Test.cinnabar"));
System.out.print("Loaded project: " + loadedProject.getName());
} catch (Exception e) {
e.printStackTrace();
}
// Try to create a project and save it to the hard drive.
Project newProject = new Project(new File("New.cinnabar"));
try {
ProjectRepository.save(newProject, new File("New.cinnabar"));
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
project.xsd
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://hg.flyingwhales.nl/cinnabar/schemas/project.xsd"
xmlns="http://hg.flyingwhales.nl/cinnabar/schemas/project.xsd"
elementFormDefault="qualified">
<xs:element name="Project">
<xs:complexType>
<xs:sequence>
<xs:element name="DataPath" type="xs:string" />
<xs:element name="ScriptPath" type="xs:string" />
<xs:element name="ArtPath" type="xs:string" />
<xs:element name="SFXPath" type="xs:string" />
<xs:element name="BGMPath" type="xs:string" />
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="type" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:schema>
Test.cinnabar
<?xml version="1.0" encoding="UTF-8"?>
<Project name="Test project" type="Standalone"
xmlns="http://hg.flyingwhales.nl/cinnabar/schemas/project.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://hg.flyingwhales.nl/cinnabar/schemas/project.xsd">
<DataPath>Data</DataPath>
<ScriptPath>Data/Scripts</ScriptPath>
<ArtPath>Art</ArtPath>
<SFXPath>Sound/SFX</SFXPath>
<BGMPath>Sound/BGM</BGMPath>
</Project>
只需运行代码,就会产生错误。确保project.xsd在工作目录中。
答案 0 :(得分:3)
可以在`Project.java中添加propOrder
。
package nl.flyingwhales.hg.cinnabar.schemas.project;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"dataPath",
"scriptPath",
"artPath",
"sfxPath",
"bgmPath"
})
@XmlRootElement(name = "Project")
public class Project {
@XmlElement(name = "DataPath", required = true)
protected String dataPath;
@XmlElement(name = "ScriptPath", required = true)
protected String scriptPath;
@XmlElement(name = "ArtPath", required = true)
protected String artPath;
@XmlElement(name = "SFXPath", required = true)
protected String sfxPath;
@XmlElement(name = "BGMPath", required = true)
protected String bgmPath;
@XmlAttribute(name = "name", required = true)
protected String name;
@XmlAttribute(name = "type", required = true)
protected String type;
//getter and setters
}
答案 1 :(得分:2)
两件事:
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED
propOrder
来正确排序元素。 package-info.java
:
@XmlSchema(namespace = "http://hg.flyingwhales.nl/cinnabar/schemas/project.xsd", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.flyingwhales;
import javax.xml.bind.annotation.XmlSchema;
Project.java
:
@XmlRootElement(name = "Project")
@XmlType(name = "", propOrder = {
"dataPath",
"scriptPath",
"artPath",
"sfxPath",
"bgmPath"
})
public class Project { ... }
问题的核心是elementFormDefault=QUALIFIED
。这导致局部元素在空命名空间中被编组,因此模式验证和后续的解组失败。