InWrapper.java 8.84 KB
package ipipan.clarin.tei.impl.io.read;

import ipipan.clarin.tei.impl.io.IdValuePair;
import ipipan.clarin.tei.impl.utils.XMLConst;

import java.io.IOException;
import java.io.Reader;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.xml.stream.Location;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import org.apache.log4j.Logger;

/**
 * 
 * @author mlenart
 */
class InWrapper {

	private final static Logger logger = Logger.getLogger(InWrapper.class);
	private final static XMLInputFactory factory = XMLInputFactory
			.newInstance();
	static {
		factory.setProperty("javax.xml.stream.isCoalescing", true);
	}
	private final XMLStreamReader xsr;
	private final String filename;

	InWrapper(Reader reader, String filename) throws XMLStreamException,
			IOException {
		this.xsr = factory.createXMLStreamReader(new ReaderWrapper(reader));
		this.filename = filename;
	}

	public boolean isStart() {
		return xsr.isStartElement();
	}

	public boolean isStart(String name) throws XMLStreamException {
		return xsr.isStartElement() && getName().equals(name);
	}

	public boolean isStart(String prefix, String name)
			throws XMLStreamException {
		return isStart(name) && xsr.getName().getPrefix().equals("xi");
	}

	public boolean isEnd() {
		return xsr.isEndElement();
	}

	public boolean isEnd(String name) throws XMLStreamException {
		return isEnd() && getName().equals(name);
	}

	public boolean isEndFS() throws XMLStreamException {
		return isEnd() && getName().equals("fs");
	}

	public boolean isEndDocument() {
		return xsr.getEventType() == XMLStreamConstants.END_DOCUMENT;
	}

	public boolean isStartF(String name) throws XMLStreamException {
		return isStart() && getName().equals("f")
				&& name.equals(getAttr("name"));
	}

	public boolean isStartFS(String type) throws XMLStreamException {
		return isStart() && getName().equals("fs")
				&& type.equals(getAttr("type"));
	}

	public boolean isStartParagraph() throws XMLStreamException {
		return isStart()
				&& Arrays.asList("p", "u", "ab", "div").contains(getName())
				&& getXmlId() != null;
	}

	boolean isCharacters() {
		return xsr.isCharacters();
	}

	boolean isWhitespace() {
		return xsr.isWhiteSpace();
	}

	public String getName() throws XMLStreamException {
		require("start element or end element",
				xsr.isStartElement() || xsr.isEndElement());
		return xsr.getLocalName();
	}

	public Location getLocation() {
		return xsr.getLocation();
	}

	void requireAttr(String name) throws XMLStreamException {
		getAttr(name, true);
	}

	public String getAttr(String name) throws XMLStreamException {
		return getAttr(name, false);
	}

	private String getAttr(String name, boolean force)
			throws XMLStreamException {
		String res = xsr.getAttributeValue(null, name);
		if (force) {
			require("attribute " + name, res != null);
		}
		return res;
	}

	public boolean getBoolNKJPAttr(String name) {
		String val = xsr.getAttributeValue(XMLConst.NKJP_NS, name);
		if (val == null) {
			return false;
		} else {
			return val.equalsIgnoreCase("true");
		}
	}

	public String getXmlId() {
		return xsr.getAttributeValue(XMLConst.XML_NS, "id");
	}

	public String getText() {
		if (xsr.hasText())
			return xsr.getText();
		else
			return "";
	}

	public void requireStart(String name) throws XMLStreamException {
		if (!isStart(name)) {
			fail("start element <" + name + ">");
		}
	}

	public void requireStartF(String name) throws XMLStreamException {
		if (!isStartF(name)) {
			fail(String.format("<f name='%s'> start element", name));
		}
	}

	public void requireStartFS(String type) throws XMLStreamException {
		xsr.require(XMLStreamConstants.START_ELEMENT, XMLConst.TEI_NS, "fs");
		require("@type=" + type, getAttr("type", true).equals(type));
	}

	public IdValuePair readStringF() throws XMLStreamException {
		require("<f> start element", getName().equals("f"));
		String id = getXmlId();
		xsr.nextTag();
		requireStart("string");
		String value = xsr.getElementText();
		xsr.nextTag();
		requireEnd(); // f
		return new IdValuePair(id, value);
	}

	public IdValuePair readSymbolF() throws XMLStreamException {
		require("<f> start element", getName().equals("f"));
		String id = getXmlId();
		xsr.nextTag();
		requireStart("symbol");
		String value = getAttr("value");
		xsr.nextTag();
		requireEnd(); // symbol
		xsr.nextTag();
		requireEnd(); // f
		return new IdValuePair(id, value);
	}

	public boolean readBinaryF() throws XMLStreamException {
		require("<f> start element", getName().equals("f"));
		xsr.nextTag();
		requireStart("binary");
		requireAttr("value");
		String value = getAttr("value");
		xsr.nextTag();
		requireEnd(); // symbol
		xsr.nextTag();
		requireEnd(); // f
		return value.equalsIgnoreCase("true");
	}

	public String readFValue() throws XMLStreamException {
		require("<f> start element", getName().equals("f"));
		requireAttr("fVal");
		String res = getAttr("fVal");
		List<String> split = Arrays.asList(res.split("#"));
		res = split.get(split.size() - 1);
		xsr.nextTag();
		requireEnd(); // f
		return res;
	}

	public Map<String, String> readFSymbolsList() throws XMLStreamException {
		Map<String, String> res = new LinkedHashMap<String, String>();
		boolean valt = false;
		require("<f> start element", getName().equals("f"));
		xsr.nextTag();
		if (isStart("vAlt")) {
			valt = true;
			xsr.nextTag();
		}
		while (isStart("symbol")) {
			String id = getXmlId();
			String value = getAttr("value");
			res.put(id, value);
			xsr.nextTag();
			requireEnd(); // symbol
			xsr.nextTag();
		}
		if (valt) {
			requireEnd(); // vAlt
			xsr.nextTag();
		}
		requireEnd(); // f
		return res;
	}

	public void readUntilEnd() throws XMLStreamException {
		xsr.require(XMLStreamConstants.START_ELEMENT, null, null);
		int depth = 1;
		while (depth > 0) {
			xsr.next();
			if (isStart()) {
				depth++;
			} else if (isEnd()) {
				depth--;
			}
		}
	}

	private void require(String expected, boolean b) throws XMLStreamException {
		if (!b) {
			fail(expected);
		}
	}

	public void requireEnd() throws XMLStreamException {
		if (!xsr.isEndElement()) {
			fail("end element");
		}
	}

	public void requireEnd(String name) throws XMLStreamException {
		require(String.format("</%s> end element", name), isEnd(name));
	}

	public boolean hasNext() throws XMLStreamException {
		return xsr.hasNext();
	}

	public void next() throws XMLStreamException {
		// debug();
		if (!xsr.hasNext()) {
			fail("something");
		}
		do {
			xsr.next();
		} while (xsr.isWhiteSpace());
	}

	public void nextTag() throws XMLStreamException {
		// debug();
		xsr.nextTag();
	}

	public void fail(String expected) throws XMLStreamException {
		String errString = "Expected %s but got %s at line:%d column:%d";
		if (filename != null) {
			errString += " in " + filename;
		}
		throw new XMLStreamException(String.format(errString, expected,
				currentEvent2String(), xsr.getLocation().getLineNumber(), xsr
						.getLocation().getColumnNumber()));
	}

	private String currentEvent2String() throws XMLStreamException {
		switch (xsr.getEventType()) {
		case (XMLStreamReader.START_ELEMENT):
			if ("f".equals(getName())) {
				return String.format("<f name=\"%s\"> start element",
						getAttr("name"));
			} else if ("fs".equals(getName())) {
				return String.format("<fs type=\"%s\"> start element",
						getAttr("type"));
			} else {
				return String.format("<%s> start element", getName());
			}
		case (XMLStreamReader.END_ELEMENT):
			return String.format("</%s> end element", getName());
		case (XMLStreamReader.CHARACTERS):
			return String.format("'%s' characters", getText());
		case (XMLStreamReader.COMMENT):
			return String.format("'%s' comment", xsr.getText());
		case (XMLStreamReader.CDATA):
			return String.format("'%s' CDATA", xsr.getText());
		case (XMLStreamReader.END_DOCUMENT):
			return "end of stream";
		case (XMLStreamReader.PROCESSING_INSTRUCTION):
			return "processing instruction";
		case (XMLStreamReader.DTD):
			return "DTD";
		default:
			return "something else";
		}
	}

	public void close() throws XMLStreamException {
		xsr.close();
	}

	void debug() throws XMLStreamException {
		if (xsr.isStartElement()) {
			StringBuilder sb = new StringBuilder("<");
			sb.append(getName());
			for (int i = 0; i < xsr.getAttributeCount(); i++) {
				String name = xsr.getAttributeName(i).getLocalPart();
				String val = xsr.getAttributeValue(i);
				sb.append(String.format(" %s=\"%s\"", name, val));
			}
			sb.append(">");
			logger.trace(sb.toString());
		} else if (xsr.isEndElement()) {
			logger.trace("</" + xsr.getLocalName() + ">");
		} else if (xsr.isCharacters()) {
			logger.trace(xsr.getText());
		} else if (xsr.getEventType() == XMLStreamConstants.START_DOCUMENT) {
			logger.trace("START DOC");
		}
	}

	boolean isXInclude(String string) {
		throw new UnsupportedOperationException("Not yet implemented");
	}

}