找到了以元素'元素'开头的无效内容。其中一个元素'是期待

时间:2016-11-13 10:49:48

标签: java xml xsd jaxb

我使用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在工作目录中。

2 个答案:

答案 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)

两件事:

  • 您的package-info.java缺少elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED
  • 正如@sahoora正确注意到的那样,在编组时你还需要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。这导致局部元素在空命名空间中被编组,因此模式验证和后续的解组失败。