org.eobjects.metamodel.xml.XmlSaxContentHandler Maven / Gradle / Ivy
/**
* eobjects.org MetaModel
* Copyright (C) 2010 eobjects.org
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.eobjects.metamodel.xml;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.eobjects.metamodel.data.RowPublisher;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* SAX handler for publishing records based on xpath expressions.
*
* @author Kasper Sørensen
*/
class XmlSaxContentHandler extends DefaultHandler {
private final boolean _checkAttributes;
private final String _rowXpath;
private final String[] _valueXpaths;
private final StringBuilder _pathBuilder;
private final StringBuilder _valueBuilder;
private final RowPublisher _rowPublisher;
private final Map _indexIndexes;
private final Map _indexCounters;
private volatile Object[] _rowValues;
private volatile int _xpathIndex;
public XmlSaxContentHandler(String rowXpath, RowPublisher rowPublisher,
String... valueXpaths) {
_indexCounters = new HashMap();
_indexIndexes = new HashMap();
_rowXpath = rowXpath;
_rowPublisher = rowPublisher;
_valueXpaths = valueXpaths;
_rowValues = new Object[valueXpaths.length];
boolean checkAttributes = false;
for (int i = 0; i < valueXpaths.length; i++) {
String xpath = valueXpaths[i];
if (XmlSaxDataContext.COLUMN_NAME_ROW_ID.equals(xpath)) {
// we use the indexing mechanism also for the row id.
xpath = "index(" + xpath + ")";
}
if (xpath.startsWith("index(") && xpath.endsWith(")")) {
xpath = xpath.substring("index(".length(), xpath.length() - 1);
_indexCounters.put(xpath, new AtomicInteger(-1));
_indexIndexes.put(xpath, i);
} else if (xpath.indexOf('@') != -1) {
checkAttributes = true;
}
}
_checkAttributes = checkAttributes;
_xpathIndex = -1;
_pathBuilder = new StringBuilder();
_valueBuilder = new StringBuilder();
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
_pathBuilder.append('/');
_pathBuilder.append(qName);
if (_checkAttributes) {
for (int i = 0; i < attributes.getLength(); i++) {
String attributeName = attributes.getQName(i);
String attributeValue = attributes.getValue(i);
startAttribute(attributeName, attributeValue);
endAttribute(attributeName, attributeValue);
}
}
String xpath = _pathBuilder.toString();
AtomicInteger indexCounter = _indexCounters.get(xpath);
if (indexCounter != null) {
indexCounter.incrementAndGet();
}
_xpathIndex = indexOfXpath(xpath);
}
private int indexOfXpath(String path) {
if (path == null || path.length() == 0) {
return -1;
}
for (int i = 0; i < _valueXpaths.length; i++) {
if (path.equals(_valueXpaths[i])) {
return i;
}
}
return -1;
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if (_xpathIndex != -1) {
_valueBuilder.append(ch, start, length);
}
}
private void startAttribute(String attributeName, String attributeValue) {
_pathBuilder.append('@');
_pathBuilder.append(attributeName);
int indexOfXpath = indexOfXpath(_pathBuilder.toString());
if (indexOfXpath != -1) {
_rowValues[indexOfXpath] = attributeValue;
}
}
private void endAttribute(String attributeName, String attributeValue) {
_pathBuilder.setLength(_pathBuilder.length() - attributeName.length()
- 1);
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if (_xpathIndex != -1) {
_rowValues[_xpathIndex] = _valueBuilder.toString().trim();
}
_xpathIndex = -1;
_valueBuilder.setLength(0);
if (_rowXpath.equals(_pathBuilder.toString())) {
insertRowIndexes();
boolean more = _rowPublisher.publish(_rowValues);
if (!more) {
throw new XmlStopParsingException();
}
_rowValues = new Object[_valueXpaths.length];
}
_pathBuilder.setLength(_pathBuilder.length() - qName.length() - 1);
}
private void insertRowIndexes() {
Set> entrySet = _indexIndexes.entrySet();
for (Entry entry : entrySet) {
String xpath = entry.getKey();
Integer indexIndex = entry.getValue();
AtomicInteger indexCount = _indexCounters.get(xpath);
_rowValues[indexIndex] = indexCount.get();
}
}
}