问题
I want to unmarshal an XML file to java object using JAXB. The XML file is very large and contains some nodes which I want to skip in some cases to improve performance as these elements are non editable by client java program.
A sample XML is as follows:
<Example id="10" date="1970-01-01" version="1.0">
<Properties>...</Properties>
<Summary>...</Summary>
<RawData>
<Document id="1">...</Document>
<Document id="2">...</Document>
<Document id="3">...</Document>
------
------
</RawData>
<Location></Location>
<Title></Title>
----- // more elements
</Example>
I have two use cases:
- unmarshal into Example object which contains Properties, Summaries, RawData etc. without skipping any RawData. (already done this part)
- unmarshal into Example object which exclude RawData. Elements nested in RawData is very large so do not want to read this in this use case.
Now I want to unmarshal the XML such that RawData can be skipped. I have tried the technique provided at this link.
Using technique provided in above link also skips all elements which come after RawData.
回答1:
I have fixed the issue with XMLEventReader with following code:
public class PartialXmlEventReader implements XMLEventReader {
private final XMLEventReader reader;
private final QName qName;
private boolean skip = false;
public PartialXmlEventReader(final XMLEventReader reader, final QName element) {
this.reader = reader;
this.qName = element;
}
@Override
public String getElementText() throws XMLStreamException {
return reader.getElementText();
}
@Override
public Object getProperty(final String name) throws IllegalArgumentException {
return reader.getProperty(name);
}
@Override
public boolean hasNext() {
return reader.hasNext();
}
@Override
public XMLEvent nextEvent() throws XMLStreamException {
while (isEof(reader.peek())) {
reader.nextEvent();
}
return reader.nextEvent();
}
@Override
public XMLEvent nextTag() throws XMLStreamException {
return reader.nextTag();
}
@Override
public XMLEvent peek() throws XMLStreamException {
return reader.peek();
}
@Override
public Object next() {
return reader.next();
}
@Override
public void remove() {
reader.remove();
}
@Override
public void close() throws XMLStreamException {
reader.close();
}
private boolean isEof(final XMLEvent e) {
boolean returnValue = skip;
switch (e.getEventType()) {
case XMLStreamConstants.START_ELEMENT:
final StartElement se = (StartElement) e;
if (se.getName().equals(qName)) {
skip = true;
returnValue = true;
}
break;
case XMLStreamConstants.END_ELEMENT:
final EndElement ee = (EndElement) e;
if (ee.getName().equals(qName)) {
skip = false;
}
break;
}
return returnValue;
}
}
While Unmarshalling just pass this eventReader to the unmarshal method
final JAXBContext context = JAXBContext.newInstance(classes);
final Unmarshaller um = context.createUnmarshaller();
Reader reader = null;
try {
reader = new BufferedReader(new FileReader(xmlFile));
final QName qName = new QName("RawData");
final XMLInputFactory xif = XMLInputFactory.newInstance();
final XMLEventReader xmlEventReader = xif.createXMLEventReader(reader);
final Example example =
(Example) um.unmarshal(new PartialXmlEventReader(xmlEventReader, qName));
}
} finally {
IOUtils.closeQuietly(reader);
}
回答2:
I hope this would help
try {
// First create a new XMLInputFactory
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
// Setup a new eventReader
InputStream in = new FileInputStream("myXml");
XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
// Read the XML document
Example example = null;
while (eventReader.hasNext()) {
XMLEvent event = eventReader.nextEvent();
if (event.isStartElement()) {
StartElement startElement = event.asStartElement();
// If we have a example element we create a new example
if (startElement.getName().getLocalPart().equals("Example")) {
example = new Example();
// We read the attributes from this tag and add the date
// and id attribute to our object
Iterator<Attribute> attributes = startElement
.getAttributes();
while (attributes.hasNext()) {
Attribute attribute = attributes.next();
if (attribute.getName().toString().equals("date")) {
example.setDate(attribute.getValue());
} else if (attribute.getName().toString().equals("id")) {
example.setId(attribute.getValue());
}
}
}
//get the Properties tag and add to object example
if (event.isStartElement()) {
if (event.asStartElement().getName().getLocalPart()
.equals("Properties")) {
event = eventReader.nextEvent();
example.setProperites(event.asCharacters().getData());
continue;
}
}
//get the Summary tag and add to object example
if (event.asStartElement().getName().getLocalPart()
.equals("Summary")) {
event = eventReader.nextEvent();
example.setSummary(event.asCharacters().getData());
continue;
}
// when you encounter the Rawdata tag just continue
//without adding it to the object created
if (event.asStartElement().getName().getLocalPart()
.equals("Rawdata")) {
event = eventReader.nextEvent();
// don't do anything
continue;
}
//get the location tag and add to object example
if (event.asStartElement().getName().getLocalPart()
.equals("Location")) {
event = eventReader.nextEvent();
example.setLocation(event.asCharacters().getData());
continue;
}
// read and add other elements that can be added
}
// If we reach the end of an example element/tag i.e closing tag
if (event.isEndElement()) {
EndElement endElement = event.asEndElement();
if (endElement.getName().getLocalPart().equals("Example")) {
//do something
}
}
}
} catch (FileNotFoundException | XMLStreamException e) {
}
来源:https://stackoverflow.com/questions/16656809/partial-unmarshalling-of-an-xml-using-jaxb-to-skip-some-xmlelement