繁体   English   中英

手动编写的 XSD 和生成的 java 类导致使用 JAXB 的 UnmarshallException

[英]Manually written XSD and generated java classes lead to an UnmarshallException using JAXB

我对 JAVA 和阅读 XML 相当陌生。 我习惯于在 C# .net 中使用 XSD 解析 XML。 调查这个主题让我可以使用 JAXB,但我无法让它工作。 我使用示例 XML 编写了一个单元测试,但这会产生一个模糊的异常(在我看来)。

所以我们有一个看起来像这样的 XSD:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Jabberpoint">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="1" maxOccurs="1" name="Slideshows" type="Slideshows" />
        <xs:element minOccurs="1" maxOccurs="1" name="Slides" type="Slides" />
        <xs:element minOccurs="0" maxOccurs="1" name="Components" type="Components" />
      </xs:sequence>
    </xs:complexType>
    <xs:keyref name="slideKeyRef" refer="slideKey">
      <xs:selector xpath="Slideshows/Slideshow/Slide" />
      <xs:field xpath="@id" />
    </xs:keyref>
    <xs:key name="slideKey">
      <xs:selector xpath="Slides/Slide"/>
      <xs:field xpath="Id"/>
    </xs:key>
  </xs:element>

  <xs:complexType name="PresentationParserDTO" />

  <xs:complexType name="Slideshows">
    <xs:sequence maxOccurs="unbounded">
      <xs:element minOccurs="1" maxOccurs="unbounded" name="Slideshow" type="SlideshowParserDTO" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Slides">
    <xs:sequence maxOccurs="unbounded">
      <xs:element minOccurs="1" maxOccurs="unbounded" name="Slide" type="SlideParserDTO" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Components">
    <xs:sequence maxOccurs="unbounded">
      <xs:element minOccurs="0" maxOccurs="unbounded" name="Component" type="SlideComponentDTO" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="SlideshowParserDTO">
    <xs:complexContent mixed="false">
      <xs:extension base="PresentationParserDTO">
        <xs:sequence>
          <xs:element name="Slide" minOccurs="1" maxOccurs="unbounded">
            <xs:complexType>
              <xs:attribute name="id" type="xs:string"/>
            </xs:complexType>
          </xs:element>
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>

  <xs:complexType name="SlideParserDTO">
    <xs:complexContent mixed="false">
      <xs:extension base="PresentationParserDTO">
        <xs:sequence>
          <xs:element minOccurs="1" maxOccurs="1" name="Id" type="xs:string"/>
          <xs:element minOccurs="0" maxOccurs="unbounded" name="Component">
            <xs:complexType>
              <xs:attribute name="id" type="xs:string"/>
            </xs:complexType>
          </xs:element>
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>

  <xs:complexType name="SlideComponentDTO">
    <xs:complexContent mixed="false">
      <xs:extension base="PresentationParserDTO">
        <xs:sequence>
          <xs:element minOccurs="1" maxOccurs="1" name="Id" type="xs:string"/>
          <xs:element minOccurs="0" maxOccurs="1" name="Item" type="SlideItemParserDTO" />
          <xs:element minOccurs="0" maxOccurs="1" name="Children">
            <xs:complexType>
              <xs:sequence>
                <xs:element minOccurs="0" maxOccurs="unbounded" name="Component">
                  <xs:complexType>
                    <xs:attribute name="id" type="xs:string"/>
                  </xs:complexType>
                </xs:element>
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>

  <xs:complexType name="SlideItemParserDTO" abstract="true">
    <xs:complexContent mixed="false">
      <xs:extension base="PresentationParserDTO" />
    </xs:complexContent>
  </xs:complexType>

  <xs:complexType name="LexicalItemParserDTO" abstract="true">
    <xs:complexContent mixed="false">
      <xs:extension base="SlideItemParserDTO">
        <xs:sequence>
          <xs:element minOccurs="1" maxOccurs="1" name="Text" type="xs:string" />
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>

  <xs:complexType name="Text">
    <xs:complexContent mixed="false">
      <xs:extension base="LexicalItemParserDTO" />
    </xs:complexContent>
  </xs:complexType>

  <xs:complexType name="Title">
    <xs:complexContent mixed="false">
      <xs:extension base="LexicalItemParserDTO" />
    </xs:complexContent>
  </xs:complexType>

  <xs:complexType name="Media">
    <xs:complexContent mixed="false">
      <xs:extension base="SlideItemParserDTO">
        <xs:sequence>
          <xs:element minOccurs="1" maxOccurs="1" name="Source" type="xs:string" />
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>

  <xs:complexType name="Table">
    <xs:complexContent mixed="false">
      <xs:extension base="SlideItemParserDTO">
        <xs:sequence>
          <xs:element minOccurs="1" maxOccurs="unbounded" name="tr" type="TableRowParserDTO" />
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>

  <xs:complexType name="TableRowParserDTO">
    <xs:sequence>
      <xs:element minOccurs="1" maxOccurs="unbounded" name="td" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

我从中生成了这样的类:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "slideshows",
    "slides",
    "components"
})
@XmlRootElement(name = "Jabberpoint")
public class Jabberpoint {

    @XmlElement(name = "Slideshows", required = true)
    protected Slideshows slideshows;
    @XmlElement(name = "Slides", required = true)
    protected Slides slides;
    @XmlElement(name = "Components")
    protected Components components;

    /**
     * Gets the value of the slideshows property.
     * 
     * @return
     *     possible object is
     *     {@link Slideshows }
     *     
     */
    public Slideshows getSlideshows() {
        return slideshows;
    }

    /**
     * Sets the value of the slideshows property.
     * 
     * @param value
     *     allowed object is
     *     {@link Slideshows }
     *     
     */
    public void setSlideshows(Slideshows value) {
        this.slideshows = value;
    }

    /**
     * Gets the value of the slides property.
     * 
     * @return
     *     possible object is
     *     {@link Slides }
     *     
     */
    public Slides getSlides() {
        return slides;
    }

    /**
     * Sets the value of the slides property.
     * 
     * @param value
     *     allowed object is
     *     {@link Slides }
     *     
     */
    public void setSlides(Slides value) {
        this.slides = value;
    }

    /**
     * Gets the value of the components property.
     * 
     * @return
     *     possible object is
     *     {@link Components }
     *     
     */
    public Components getComponents() {
        return components;
    }

    /**
     * Sets the value of the components property.
     * 
     * @param value
     *     allowed object is
     *     {@link Components }
     *     
     */
    public void setComponents(Components value) {
        this.components = value;
    }
}

和一个看起来像这样的解析器:

public class XMLPresentationParser {
    public Jabberpoint Parse(InputStream inputstream) throws MalformedURLException, SAXException, JAXBException {
        var jc = JAXBContext.newInstance(PresentationParserDTO.class);
        var unmarshaller = jc.createUnmarshaller();

        
        var schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
        var file = new File("./src/Jabberpoint/Schema/slideshow.xsd");
        var schema = schemaFactory.newSchema(file);
        unmarshaller.setSchema(schema);

        var element = (JAXBElement<Jabberpoint>) unmarshaller.unmarshal(inputstream);
        return element.getValue();
    }
}

然后我创建了一个单元测试来检查我是否可以读取和解析一个简单的 XML 文件:

public class AllTests {

    @Test
    public void Test() throws FileNotFoundException, MalformedURLException, SAXException, JAXBException {
        // Assert
        var target = new XMLPresentationParser();
        var inputstream = new FileInputStream(getClass().getResource("slideshow.xml").getPath());
        // Act
        var result = target.Parse(inputstream);
        
        // Assert
        assertNotNull(result);
        // TODO: real assert
    }
}

使用这个简单的示例 XML 文件:

<?xml version="1.0" encoding="utf-8"?>
<Jabberpoint>
  <Slideshows>
    <Slideshow>
      <Slide id="d62f4edd-10d3-4f2d-95b7-ca5c75525688" />
      <Slide id="40a63503-ed5c-4e8a-b170-dec630f28798" />
    </Slideshow>

    <Slideshow>
      <Slide id="2a4aef8c-22b4-4439-bbbe-ef27a90d64c1" />
      <Slide id="40a63503-ed5c-4e8a-b170-dec630f28798" />
    </Slideshow>
  </Slideshows>
  <Slides>
    <Slide>
      <Id>d62f4edd-10d3-4f2d-95b7-ca5c75525688</Id>
      <Component id="822a7698-2a87-4c16-88fe-7b416fd64a20" />
      <Component id="e0049245-7346-4952-b8ce-05e25b6f3331"/>
    </Slide>

    <Slide>
      <Id>2a4aef8c-22b4-4439-bbbe-ef27a90d64c1</Id>
      <Component id="a264f972-e24e-4674-85c3-e08ff6f29d76"/>
      <Component id="e0049245-7346-4952-b8ce-05e25b6f3331"/>
    </Slide>

    <Slide>
      <Id>40a63503-ed5c-4e8a-b170-dec630f28798</Id>
      <Component id="c70121d9-63a7-49d4-9edd-afd5d314a3f7" />
    </Slide>
  </Slides>

  <Components>
    <Component>
      <Id>822a7698-2a87-4c16-88fe-7b416fd64a20</Id>
      <Item xsi:type="Title">
        <Text>This is Slideshow number 1</Text>
      </Item>
    </Component>

    <Component>
      <Id>a264f972-e24e-4674-85c3-e08ff6f29d76</Id>
      <Item xsi:type="Title">
        <Text>This is Slideshow number 2</Text>
      </Item>
    </Component>

    <Component>
      <Id>c70121d9-63a7-49d4-9edd-afd5d314a3f7</Id>
      <Item xsi:type="Title">
        <Text>This Component contains some images and a table</Text>
      </Item>
      <Children>
        <Component id="18da47d6-aebe-4525-af2e-20418bb0b1d8" />
        <Component id="5ba057c8-857e-4d3e-9466-9f27c4c26676" />
        <Component id="e0049245-7346-4952-b8ce-05e25b6f3331"/>
      </Children>
    </Component>

    <Component>
      <Id>18da47d6-aebe-4525-af2e-20418bb0b1d8</Id>
      <Item xsi:type="Media">
        <Source>img1.jpg</Source>
      </Item>
    </Component>

    <Component>
      <Id>5ba057c8-857e-4d3e-9466-9f27c4c26676</Id>
      <Item xsi:type="Media">
        <Source>img1.jpg</Source>
      </Item>
    </Component>

    <Component>
      <Id>e0049245-7346-4952-b8ce-05e25b6f3331</Id>
      <Item xsi:type="Table">
        <tr>
          <td>Apples</td>
          <td>Bananas</td>
        </tr>
      </Item>
    </Component>
  </Components>

</Jabberpoint>

运行此测试会产生以下错误。 为什么我收到这个错误? 有没有更好的方法来使用 XSD 读取 XML? 我主要使用 JAXB,所以我不必自己编写解析器。

AllTests
Jabberpoint.Infrastructure.Tests.AllTests
Test(Jabberpoint.Infrastructure.Tests.AllTests)
javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"Jabberpoint"). Expected elements are (none)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:741)
    at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:262)
    at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:257)
    at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:124)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1149)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:574)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:556)
    at com.sun.xml.bind.v2.runtime.unmarshaller.ValidatingUnmarshaller.startElement(ValidatingUnmarshaller.java:102)
    at com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:168)
    at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:510)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:374)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDriver.scanRootElementHook(XMLNSDocumentScannerImpl.java:613)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:3078)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:836)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:605)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:541)
    at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:888)
    at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:824)
    at java.xml/com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
    at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1216)
    at java.xml/com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:635)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:258)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:229)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:170)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:209)
    at Jabberpoint.Infrastructure.XMLPresentationParser.Parse(XMLPresentationParser.java:31)
    at Jabberpoint.Infrastructure.Tests.AllTests.Test(AllTests.java:28)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
    at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:40)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
    at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
    at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
    at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
    at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:80)
    at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:71)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:137)
    at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)

只需将xsi:命名空间添加到 XML 的根元素即可。
所以在你的 XML 更改中

<?xml version="1.0" encoding="utf-8"?>
<Jabberpoint>
  <Slideshows>
    <Slideshow>
    ...

<?xml version="1.0" encoding="utf-8"?>
<Jabberpoint xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Slideshows>
    <Slideshow>
    ...

然后 XSD 将验证您的 XML 文件。
可能还有其他方法可以将xsi:命名空间添加到您的 XML 中,但这是最简单的一种。

您正在为错误的顶级类创建 JAXContext:

var jc = JAXBContext.newInstance(PresentationParserDTO.class);

应该:

var jc = JAXBContext.newInstance(Jabberpoint.class);

此外,解组步骤的转换应该是Jabberpoint ,而不是JAXBElement<Jabberpoint>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM