package org.emdev.common.xml.parsers;
import java.util.Arrays;
import org.emdev.common.xml.IContentHandler;
import org.emdev.common.xml.IXmlTagFactory;
import org.emdev.common.xml.TextProvider;
import org.emdev.common.xml.tags.XmlTag;
import com.ximpleware.NavException;
import com.ximpleware.VTDGenEx;
import com.ximpleware.VTDNavEx;
public class VTDExParser {
public void parse(final VTDGenEx inStream, final IXmlTagFactory factory, final IContentHandler handler) throws NavException {
final VTDNavEx nav = inStream.getNav();
final boolean res = nav.toElement(VTDNavEx.ROOT);
if (!res) {
return;
}
TextProvider text = null;
XmlTag tag = XmlTag.UNKNOWN;
int skipUntilSiblingOrParent = -1;
final int first = nav.getCurrentIndex();
final int last = nav.getTokenCount();
final String[] tagAttrs = new String[2];
final XmlTag[] tags = new XmlTag[1024];
final int[] range = new int[2];
int maxDepth = -1;
for (int ci = first; ci < last;) {
final int depth = nav.getTokenDepth(ci);
final int type = nav.getTokenType(ci);
if (skipUntilSiblingOrParent != -1) {
if (type == VTDNavEx.TOKEN_STARTING_TAG && depth <= skipUntilSiblingOrParent) {
skipUntilSiblingOrParent = -1;
} else {
ci++;
continue;
}
}
if (type == VTDNavEx.TOKEN_STARTING_TAG) {
final char[] buf = nav.toRawString(ci, range);
tag = factory.getTagByName(buf, range[0], range[1]);
for (int d = maxDepth; d >= depth; d--) {
if (tags[d] != null) {
handler.endElement(tags[d]);
tags[d] = null;
}
}
tags[depth] = tag;
maxDepth = depth;
if (tag == XmlTag.UNKNOWN) {
skipUntilSiblingOrParent = depth;
ci++;
continue;
}
// Process tag attributes
if (handler.parseAttributes(tag)) {
ci = fillAtributes(nav, ci + 1, last, tag, tagAttrs);
handler.startElement(tag, tagAttrs);
} else {
ci = skipAtributes(nav, ci + 1, last);
handler.startElement(tag);
}
continue;
}
for (int d = maxDepth; d > depth; d--) {
if (tags[d] != null) {
handler.endElement(tags[d]);
tags[d] = null;
}
}
maxDepth = depth;
if (type == VTDNavEx.TOKEN_CHARACTER_DATA || type == VTDNavEx.TOKEN_CDATA_VAL) {
if (tag.processText && !handler.skipCharacters()) {
final char[] buf = nav.toRawString(ci, range);
if (text ==null) {
text = new TextProvider(buf);
}
handler.characters(text, range[0], range[1]);
}
ci++;
continue;
}
ci++;
}
for (int d = maxDepth; d >= 0; d--) {
if (tags[d] != null) {
handler.endElement(tags[d]);
tags[d] = null;
}
}
inStream.clear();
}
private int skipAtributes(final VTDNavEx nav, final int first, final int last) throws NavException {
for (int inner = first; inner < last; inner++) {
final int innerType = nav.getTokenType(inner);
switch (innerType) {
case VTDNavEx.TOKEN_ATTR_NAME:
case VTDNavEx.TOKEN_ATTR_NS:
case VTDNavEx.TOKEN_ATTR_VAL:
break;
default:
return inner;
}
}
return last;
}
private int fillAtributes(final VTDNavEx nav, final int first, final int last, final XmlTag tag,
final String[] tagAttrs) throws NavException {
final int[] range = new int[2];
for (int i = 0; i < tag.attributes.length; i++) {
tagAttrs[i] = null;
}
for (int inner = first; inner < last; inner++) {
final int innerType = nav.getTokenType(inner);
switch (innerType) {
case VTDNavEx.TOKEN_ATTR_NAME:
final char[] nameBuf = nav.toRawString(inner, range);
final String[] qName = new String(nameBuf, range[0], range[1]).split(":");
final String attrName = qName[qName.length - 1];
final int attrIndex = Arrays.binarySearch(tag.attributes, attrName);
if (attrIndex >= 0) {
final char[] valBuf = nav.toRawString(inner + 1, range);
final String attrValue = new String(valBuf, range[0], range[1]);
tagAttrs[attrIndex] = attrValue;
}
inner++;
break;
case VTDNavEx.TOKEN_ATTR_NS:
case VTDNavEx.TOKEN_ATTR_VAL:
break;
default:
return inner;
}
}
return last;
}
}