Skip to content

Instantly share code, notes, and snippets.

@ufuk
Last active November 12, 2021 13:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ufuk/2872b6b115c281b18a4633b1866f1bc6 to your computer and use it in GitHub Desktop.
Save ufuk/2872b6b115c281b18a4633b1866f1bc6 to your computer and use it in GitHub Desktop.
Various XML utilities, such as unmarshal and consume XML input stream by target element name (and -optional- target element depth).
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.util.StreamReaderDelegate;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class XmlUtils {
public static <T> void unMarshalAndConsume(InputStream inputStream, Class<T> targetClass, String targetElementName, Consumer<T> consumer) throws Exception {
unMarshalAndConsume(inputStream, targetClass, targetElementName, null, consumer);
}
public static <T> void unMarshalAndConsume(InputStream inputStream, Class<T> targetClass, String targetElementName, Integer targetElementDepth, Consumer<T> consumer) throws Exception {
XMLStreamReader xmlStreamReader = null;
try {
final XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory();
xmlStreamReader = xmlInputFactory.createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(targetClass).createUnmarshaller();
int currentDepth = 0;
while (xmlStreamReader.hasNext()) {
xmlStreamReader.next();
if (xmlStreamReader.isStartElement()) {
currentDepth++;
if (xmlStreamReader.getLocalName().equals(targetElementName) && (Objects.isNull(targetElementDepth) || targetElementDepth == currentDepth)) {
T value = unmarshaller.unmarshal(xmlStreamReader, targetClass).getValue();
consumer.accept(value);
}
} else if (xmlStreamReader.isEndElement()) {
currentDepth--;
}
}
} finally {
if (xmlStreamReader != null) {
xmlStreamReader.close();
}
}
}
public static <T> List<T> unMarshalAndList(InputStream inputStream, Class<T> targetClass, String targetElementName) throws Exception {
return unMarshalAndList(inputStream, targetClass, targetElementName, null);
}
public static <T> List<T> unMarshalAndList(InputStream inputStream, Class<T> targetClass, String targetElementName, Integer targetElementDepth) throws Exception {
final List<T> results = new ArrayList<>();
unMarshalAndConsume(inputStream, targetClass, targetElementName, targetElementDepth, results::add);
return results;
}
public static String toString(Source xmlSource) {
try {
final StringWriter writer = new StringWriter();
final StreamResult result = new StreamResult(writer);
final Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(xmlSource, result);
return writer.toString();
} catch (TransformerException e) {
throw new RuntimeException("XML source couldn't be transformed to String", e);
}
}
public static <T> T unMarshalToTypeByIgnoringNameSpace(Source xmlSource, Class<T> targetClass) throws Exception {
final NameSpaceIgnoringXMLStreamReader streamReader = new NameSpaceIgnoringXMLStreamReader(XMLInputFactory.newFactory().createXMLStreamReader(xmlSource));
final Unmarshaller unmarshaller = JAXBContext.newInstance(targetClass).createUnmarshaller();
return unmarshaller.unmarshal(streamReader, targetClass).getValue();
}
static class NameSpaceIgnoringXMLStreamReader extends StreamReaderDelegate {
public NameSpaceIgnoringXMLStreamReader(XMLStreamReader reader) {
super(reader);
}
@Override
public String getAttributeNamespace(int arg0) {
return StringUtils.EMPTY;
}
@Override
public String getNamespaceURI() {
return StringUtils.EMPTY;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment