Написанные вручную XSD и сгенерированные классы java приводят к исключению UnmarshallException с использованием JAXB - PullRequest
0 голосов
/ 16 марта 2020

Я довольно новичок в JAVA и читаю XML. Я привык разбирать XML с помощью XSD в C#. net. Расследуя на этом топи c, позвольте мне использовать 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>

From которые я сгенерировал классы так:

@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 file:

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 file:

<?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>

Запуск этого теста приводит к следующей ошибке. Почему я получаю эту ошибку? И есть ли лучшие способы чтения XML с использованием XSD? Я использую 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)

Ответы [ 2 ]

1 голос
/ 17 марта 2020

Вы создаете JAXContext для неправильного класса верхнего уровня:

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

должно быть:

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

Кроме того, приведение шага демаршаллинга должно быть к Jabberpoint, а не JAXBElement<Jabberpoint>.

1 голос
/ 16 марта 2020

Просто добавьте пространство имен xsi: к элементу root вашего 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, но это самый простой.

...