簡體   English   中英

使用 JAXB 解組大 xml 文件

[英]Unmarshal big xml files using JAXB

我有 1-2MB xml 個文件,我想將它們加載到對象列表中。 我想通過 JAXB 來完成,因為我有合適的 XSD,只有在加載這些文件時才會出現問題,因為它會拋出錯誤,說某處有未關閉的標簽,或者類似的東西,當我檢查文件時,沒有那里的錯誤。 當我加載大小為 40KB 的文件時,沒有問題,一切都在正確加載。 所以我知道在解組較大文件時 jaxb 中存在問題。 這個有什么吃法嗎? 另一種解組方式不太可能包含在游戲中,因為每個 xml 文件的結構和對象都與我用 XSD 創建的略有不同。

xml個文件的結構:

<Request>
  <Header>
    <Name> </Name>
      <Id> </Id>
  </Header>
  <RequestItems>
   <Request>
     <Header>
       <Name> </Name>
       <Id> </Id>
     </Header>
     <ObjectName>
       <City> </City>
       <Street> </Street>
     </ObjectName>
     </Request>
    </RequestItems>
 </Request>

在 RequestItems 標簽內有一個 Request 對象列表,在 Request ObjectName 對象中它因文件而異。

我以最簡單的方式執行 unmrashal,對於較小的文件,它工作正常,而較大的文件有奇怪的語法錯誤,但我知道它只是削減行,因為它太長,因此存在語法錯誤。

JAXBContext jaxbContext = JAXBContext.newInstance (Request.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller ();
Request request = (Request) jaxbUnmarshaller.unmarshal (xmlFile);

如果我正確理解了您的問題,那么這應該可行。 我使用了 Moxy,它是 Jaxb 的擴展和 Project Lombok 的 Getter setter。

想象以下是具有不同結構request.xml的大型 XML :

<request>
    <person>
        <name>Batman</name>
        <age>29</age>
        <job>IT</job>
    </person>
    <animal>
        <name>Tommy</name>
        <age>5</age>
        <type>Dog</type>
    </animal>
    <person>
        <name>Superman</name>
        <age>30</age>
        <job>HR</job>
    </person>
</request>

以下是相關的類和接口:

import jakarta.xml.bind.annotation.XmlSeeAlso;

@XmlSeeAlso({Person.class, Animal.class})
public interface XmlSupportExtension {
    Object xmlSupport();
}

import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlTransient;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@NoArgsConstructor
@AllArgsConstructor
@XmlAccessorType(XmlAccessType.FIELD)
@XmlTransient
public class Common implements Serializable {
    private String name;
    private String age;
}
import lombok.*;

@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public class Person extends Common implements XmlSupportExtension {

    private String job;

    @Override
    public Person xmlSupport() {
        return this;
    }
}
import lombok.*;

@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public class Animal extends Common implements XmlSupportExtension {
    private String type;

    @Override
    public Animal xmlSupport() {
        return this;
    }
}
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Unmarshaller;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Arrays;


public class MainStack {
    public static void main(String[] args) throws JAXBException, XMLStreamException, FileNotFoundException {
        final String[] EVENT_TYPES = new String[]{"person", "animal"};
        InputStream inputStream = MainStack.class.getResourceAsStream("/request.xml");

        //Create an instance of XMLStreamReader to read the events one-by-one
        final XMLInputFactory inputFactory = XMLInputFactory.newInstance();
        inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
        inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
        final XMLStreamReader xmlStreamReader = inputFactory.createXMLStreamReader(inputStream);

        //Create an instance of JAXBContext and Unmarshaller for unmarshalling the classes to respective event
        final Unmarshaller unmarshaller = JAXBContext.newInstance(Person.class, Animal.class).createUnmarshaller();

        //Navigate to next and start of the XML Elements
        xmlStreamReader.next();

        //Read Until the end of the file and unmarshall event-by-event
        while (xmlStreamReader.hasNext()) {

            //Check if the initial element is one of the elements from "EVENT_TYPES"
            if (xmlStreamReader.isStartElement() && Arrays.asList(EVENT_TYPES).contains(xmlStreamReader.getLocalName())) {

                //Get the event type
                final String eventType = xmlStreamReader.getLocalName();

                Object event = null;

                System.out.println(eventType);

                // Based on eventType make unmarshaller call to respective event class
                switch (eventType) {
                    case "person":
                        //Unmarshal the Person
                        event = unmarshaller.unmarshal(xmlStreamReader, Person.class).getValue();
                        break;
                    case "animal":
                        //Unmarshal the Animal
                        event = unmarshaller.unmarshal(xmlStreamReader, Animal.class).getValue();
                        break;
                    default:
                        //If NONE of the event type matches then do not convert and make a note
                        System.out.println("XML event does not match any of the required event : " + event);
                        break;
                }

                System.out.println(" After Unmarhsalling : " + event.toString());
            }

            //Move to the next event/element in InputStream
            xmlStreamReader.next();
        }
    }
}

這將產生以下 output:

person
 After Unmarhsalling : Person(super=Common(name=Batman, age=29), job=IT)
animal
 After Unmarhsalling : Animal(super=Common(name=Tommy, age=5), type=Dog)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM