/** * Copyright (C) 2012-2017 52°North Initiative for Geospatial Open Source * Software GmbH * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * * If the program is linked with libraries which are licensed under one of * the following licenses, the combination of the program with the linked * library is not considered a "derivative work" of the program: * * - Apache License, version 2.0 * - Apache Software License, version 1.0 * - GNU Lesser General Public License, version 3 * - Mozilla Public License, versions 1.0, 1.1 and 2.0 * - Common Development and Distribution License (CDDL), version 1.0 * * Therefore the distribution of the program linked with libraries licensed * under the aforementioned licenses, is permitted by the copyright holders * if the distribution is compliant with both the GNU General Public * License version 2 and the aforementioned licenses. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. */ package org.n52.sos.decode.xml.stream; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import javax.xml.namespace.QName; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import org.n52.sos.ogc.ows.OwsExceptionReport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.collect.Iterables; public abstract class XmlReader<T> { private static final Logger LOG = LoggerFactory.getLogger(XmlReader.class); private final XMLInputFactory inputFactory = XMLInputFactory.newInstance(); private XMLStreamReader reader; private QName root; private int rootCount; public T read(InputStream in) throws XMLStreamException, OwsExceptionReport { return XmlReader.this.read(this.inputFactory.createXMLStreamReader(in)); } private T read(XmlReader<?> reader) throws XMLStreamException, OwsExceptionReport { return read(reader.reader); } private T read(XMLStreamReader reader) throws XMLStreamException, OwsExceptionReport { this.reader = reader; this.root = toNextBeginTag(); String cName = this.getClass().getSimpleName(); this.rootCount = 0; if (root != null && !isEndTag()) { LOG.trace("{}: root: <{}:{}>", cName, root.getPrefix(), root.getLocalPart()); begin(); //begin may proceed to the end of the element... if (isEndTag() && tagName().equals(root)) { return finish(); } QName current; while ((current = toNextTag()) != null) { if (isStartTag()) { LOG.trace("{}: begin: <{}:{}>", cName, current.getPrefix(), current.getLocalPart()); if (current.equals(root)) { ++rootCount; } read(current); } else if (isEndTag()) { LOG.trace("{}: end: <{}:{}>", cName, current.getPrefix(), current.getLocalPart()); if (current.equals(root)) { if (rootCount == 0) { break; } else { --rootCount; } } } } } return finish(); } protected <T> T delegate(XmlReader<? extends T> reader) throws XMLStreamException, OwsExceptionReport { return reader.read(this); } private boolean isStartTag() { return this.reader.isStartElement(); } private boolean isEndTag() { return this.reader.isEndElement(); } private boolean hasNext() throws XMLStreamException { return this.reader.hasNext(); } private void next() throws XMLStreamException { this.reader.next(); } private QName toNextTag() throws XMLStreamException { if (hasNext()) { next(); return toTag(); } else { return null; } } private QName toNextBeginTag() throws XMLStreamException { while (!isStartTag() && hasNext()) { toNextTag(); } return isStartTag() ? tagName() : null; } private QName toTag() throws XMLStreamException { while (!isStartTag() && !isEndTag() && hasNext()) { next(); } return isStartTag() || isEndTag() ? tagName() : null; } protected Map<QName, String> attr() { int l = this.reader.getAttributeCount(); Map<QName, String> attr = new HashMap<>(l); for (int i = 0; i < l; ++i) { if (this.reader.isAttributeSpecified(i)) { attr.put(this.reader.getAttributeName(i), this.reader.getAttributeValue(i)); } } return attr; } protected Iterable<Optional<String>> attr(Iterable<QName> names) { return Iterables .transform(names, new Function<QName, Optional<String>>() { @Override public Optional<String> apply(QName input) { return XmlReader.this.attr(input); } }); } protected Optional<String> attr(QName qn) { return Optional.fromNullable(attr().get(qn)); } protected Optional<String> attr(String name) { return attr(new QName(name)); } protected QName tagName() { return this.reader.getName(); } protected String chars() throws XMLStreamException { return this.reader.getElementText(); } protected void begin() throws XMLStreamException, OwsExceptionReport { /* no op */ } protected abstract T finish() throws OwsExceptionReport; protected void read(QName name) throws XMLStreamException, OwsExceptionReport { ignore(); } protected void ignore() { QName name = this.reader.getName(); String cName = getClass().getSimpleName(); LOG.warn("{}: ignoring element {}:{}", cName, name.getPrefix(), name.getLocalPart()); } }