/*
* `gnu.iou.dom'
* Copyright (C) 2006 John Pritchard.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package gnu.iou.dom.impl;
/**
* <p> DOM builder.</p>
*
* @author jdp
*/
public abstract class Builder
extends gnu.iou.queue
implements gnu.iou.dom.Builder
{
/**
* <p> SAX parse events for builder </p>
*
* @author jdp
*/
public final static class Sax
extends Builder
implements gnu.iou.dom.Builder.Sax
{
private final static int NST_INIT = Integer.MIN_VALUE;
private final static int NST_ELEMENT = org.w3c.dom.Node.ELEMENT_NODE;
private final static int NST_TEXT = org.w3c.dom.Node.TEXT_NODE;
private final static int NST_DTD = Integer.MAX_VALUE;
private final static int NST_ENTITY = org.w3c.dom.Node.ENTITY_NODE;
private final static int NST_CDATA = org.w3c.dom.Node.CDATA_SECTION_NODE;
private final static int NST_COMMENT = org.w3c.dom.Node.COMMENT_NODE;
protected org.xml.sax.Locator locator;
private int state = NST_INIT;
public Sax(Document doc){
super(doc);
}
public void destroy(){
this.locator = null;
super.destroy();
}
public org.xml.sax.Locator locator(){
if (null == this.locator)
throw new gnu.iou.dom.Error.State("destroyed");
else
return this.locator;
}
public org.xml.sax.Locator locator(boolean exc){
if (null == this.locator){
if (exc)
throw new gnu.iou.dom.Error.State("destroyed");
else
return null;
}
else
return this.locator;
}
/* @see org.xml.sax.ContentHandler
*/
public final void setDocumentLocator(org.xml.sax.Locator locator){
this.locator = locator;
}
/* @see org.xml.sax.ContentHandler
*/
public final void startDocument() throws org.xml.sax.SAXException {
}
/* @see org.xml.sax.ContentHandler
*/
public final void endDocument() throws org.xml.sax.SAXException {
this.document().builderExit();
}
/* @see org.xml.sax.ContentHandler
*/
public final void startPrefixMapping (String prefix, String uri)
throws org.xml.sax.SAXException
{
}
/* @see org.xml.sax.ContentHandler
*/
public final void endPrefixMapping (String prefix) throws org.xml.sax.SAXException {
}
/* @see org.xml.sax.ContentHandler
*/
public final void startElement (String ns, String ln, String qn, org.xml.sax.Attributes atts)
throws org.xml.sax.SAXException
{
this.state = NST_ELEMENT;
ns = Node.StrictString(ns);
ln = Node.StrictString(ln);
qn = Node.StrictString(qn);
gnu.iou.dom.Document ctor = this.document();
org.xml.sax.Locator loc = this.locator(false);
//
gnu.iou.dom.Node parent = this.buildParent();
//
gnu.iou.dom.Element child = (gnu.iou.dom.Element)ctor.createElementNS(ns,qn);
//
if (null != loc){
child.setLocSystemId(loc.getSystemId());
child.setLocPublicId(loc.getPublicId());
child.setLocLineNumber(loc.getLineNumber());
child.setLocColumnNumber(loc.getColumnNumber());
}
//
this.push(child);
//
if (null != atts){
int len = atts.getLength();
if (0 < len){
org.w3c.dom.NamedNodeMap attributes = child.getAttributes();
String at_ns, at_qn;
gnu.iou.dom.Attr dat;
attlist:
for (int cc = 0; cc < len; cc++){
at_ns = atts.getURI(cc);
at_qn = atts.getQName(cc);
if ( null == at_qn || 1 > at_qn.length()){
at_qn = atts.getLocalName(cc);
if ( null == at_qn || 1 > at_qn.length())
continue attlist;
}
dat = (gnu.iou.dom.Attr)ctor.createAttributeNS(at_ns,at_qn);
dat.setParentNode(child);
dat.setNodeValue(atts.getValue(cc));
dat.setType(atts.getType(cc));
attributes.setNamedItem(dat);
}
}
}
parent.appendChild(child);
}
/* @see org.xml.sax.ContentHandler
*/
public final void endElement (String ns, String ln, String qn)
throws org.xml.sax.SAXException
{
this.state = NST_INIT;
gnu.iou.dom.Element elem = this.pop( ns, qn);
if (elem instanceof gnu.iou.dom.Builder.Post){
gnu.iou.dom.Builder.Post post = (gnu.iou.dom.Builder.Post)elem;
post.buildpost();
}
}
/* @see org.xml.sax.ContentHandler
*/
public final void characters (char src[], int ofs, int len)
throws org.xml.sax.SAXException
{
gnu.iou.dom.Node last = this.buildLast();
if (last instanceof gnu.iou.dom.CharacterData &&
this.state == last.getNodeType())
{
gnu.iou.dom.CharacterData node = (gnu.iou.dom.CharacterData)last;
if (null != src && 0 < len)
node.appendData(new String(src,ofs,len));
}
else {
String string = StringNotWS(src,ofs,len);
if (null != string){
gnu.iou.dom.Node parent = this.buildParent();
gnu.iou.dom.Node node;
String data = new String(src,ofs,len);
switch (this.state){
case NST_CDATA:
node = (gnu.iou.dom.Node)this.document().createCDATASection(data);
break;
case NST_COMMENT:
node = (gnu.iou.dom.Node)this.document().createComment(data);
break;
default:
case NST_INIT:
this.state = NST_TEXT;
//(fall-through)
case NST_TEXT:
node = (gnu.iou.dom.Node)this.document().createTextNode(data);
break;
}
parent.appendChild(node);
}
}
}
/* @see org.xml.sax.ContentHandler
*/
public final void ignorableWhitespace (char src[], int ofs, int len)
throws org.xml.sax.SAXException
{
String string = new String(src,ofs,len);
}
/* @see org.xml.sax.ContentHandler
*/
public final void processingInstruction (String target, String data)
throws org.xml.sax.SAXException
{
gnu.iou.dom.Node parent = this.buildParent();
org.w3c.dom.ProcessingInstruction node =
this.document().createProcessingInstruction(target,data);
parent.appendChild(node);
}
/* @see org.xml.sax.ContentHandler
*/
public final void skippedEntity (String name)
throws org.xml.sax.SAXException
{
gnu.iou.dom.Node parent = this.buildParent();
org.w3c.dom.EntityReference node =
this.document().createEntityReference(name);
parent.appendChild(node);
}
/* @see org.xml.sax.ext.LexicalHandler
*/
public final void startDTD( String name, String pid, String sid)
throws org.xml.sax.SAXException
{
// this.state = NST_DTD;
}
/* @see org.xml.sax.ext.LexicalHandler
*/
public final void endDTD() throws org.xml.sax.SAXException {
// this.state = NST_INIT;
}
/* @see org.xml.sax.ext.LexicalHandler
*/
public final void startEntity( String name) throws org.xml.sax.SAXException {
// this.state = NST_ENTITY;
}
/* @see org.xml.sax.ext.LexicalHandler
*/
public final void endEntity( String name) throws org.xml.sax.SAXException {
// this.state = NST_INIT;
}
/* @see org.xml.sax.ext.LexicalHandler
*/
public final void startCDATA() throws org.xml.sax.SAXException {
this.state = NST_CDATA;
}
/* @see org.xml.sax.ext.LexicalHandler
*/
public final void endCDATA() throws org.xml.sax.SAXException {
this.state = NST_INIT;
}
/* @see org.xml.sax.ext.LexicalHandler
*/
public final void comment (char src[], int ofs, int len) throws org.xml.sax.SAXException {
gnu.iou.dom.Node last = this.buildLast();
if (last instanceof gnu.iou.dom.Comment){
gnu.iou.dom.Comment node = (gnu.iou.dom.Comment)last;
if (null != src && 0 < len)
node.appendData(new String(src,ofs,len));
}
else {
gnu.iou.dom.Node parent = this.buildParent();
org.w3c.dom.Node node;
if (null != src && 0 < len)
node = this.document().createComment(new String(src,ofs,len));
else
throw new gnu.iou.dom.Error.State("xmlp-bug");
parent.appendChild(node);
}
}
}
private final static boolean USE_STACK = true;
protected gnu.iou.dom.Document doc;
private gnu.iou.queue dom;
protected Builder(gnu.iou.dom.Document doc){
super(USE_STACK);
if (null == doc)
throw new gnu.iou.dom.Error.Argument();
else {
this.doc = doc;
if (doc instanceof gnu.iou.dom.Builder.Binding){
this.dom = new gnu.iou.queue(USE_STACK);
this.dom.push(this,doc);
}
}
}
public gnu.iou.dom.Builder cloneBuilder(gnu.iou.dom.Document newp){
try {
Builder clone = (Builder)this.clone();
clone.doc = newp;
return clone;
}
catch (java.lang.CloneNotSupportedException cns){
throw new gnu.iou.dom.Error.State();
}
}
public final gnu.iou.dom.Document document(){
if (null == this.doc)
throw new gnu.iou.dom.Error.State("document:destroyed");
else
return this.doc;
}
public void destroy(){
this.doc = null;
super.clear();
if (null != this.dom)
try {
this.dom.clear();
}
finally {
this.dom = null;
}
}
public gnu.iou.dom.Element buildCurrent(boolean exc){
gnu.iou.dom.Element elem =
(gnu.iou.dom.Element)this.peek(this.doc);
if (exc){
if (null == elem)
throw new gnu.iou.dom.Error.State("Empty build stack");
else
return elem;
}
else
return elem;
}
public gnu.iou.dom.Node buildLast(){
gnu.iou.dom.Node current = this.buildParent();
if (current.hasChildNodes()){
org.w3c.dom.NodeList children = current.getChildNodes();
return (gnu.iou.dom.Node)children.item(children.getLength()-1);
}
else
return current;
}
public gnu.iou.dom.Node buildParent(){
gnu.iou.dom.Node parent = this.buildCurrent(false);
if (null == parent)
return this.document();
else
return parent;
}
public gnu.iou.dom.Element push(gnu.iou.dom.Element elem){
this.push(this.doc,elem);
//
if (elem instanceof gnu.iou.dom.Builder.Binding){
if (null == this.dom)
this.dom = new gnu.iou.queue(USE_STACK);
this.dom.push(this,elem);
}
//
return elem;
}
public gnu.iou.dom.Element pop(String ns, String qn){
gnu.iou.dom.Element re =
(gnu.iou.dom.Element)this.pop(this.doc);
//
if (null != this.dom && re == this.dom.peek(this))
this.dom.pop(this);
//
if (re.getNodeName2().equals(qn))
return re;
else
throw new gnu.iou.dom.Error.State("basic-document:build-stack-order");
}
public final gnu.iou.dom.Builder.Binding lastBinding(){
if (null == this.dom)
return null;
else
return (gnu.iou.dom.Builder.Binding)this.dom.peek(this);
}
public final gnu.iou.dom.Builder.Binding prevBinding(){
if (null == this.dom)
return null;
else
return (gnu.iou.dom.Builder.Binding)this.dom.peek(this,1);
}
public final gnu.iou.dom.Builder.Binding popBinding(){
if (null != this.dom)
return (gnu.iou.dom.Builder.Binding)this.dom.pop(this.doc);
else
return null;
}
/**
* <p> Unicode whitespace is defined as any of the following characters.
*
* <pre>
* 0009- 000D Control-0009, ..., Control-000D
* 0020 SPACE
* 0085 Control-0085
* 00A0 NON-BREAKING SPACE
* 1680 OGHAM SPACE MARK
* 180E MONGOLIAN VOWEL SEPARATOR
* 2000- 200A EN QUAD, ..., HAIR SPACE
* 2028 LINE SEPARATOR
* 2029 PARAGRAPH SEPARATOR
* 202F NARROW NON-BREAKING SPACE
* 205F MEDIUM MATHEMATICAL SPACE
* 3000 IDEOGRAPHIC SPACE
* </pre>
* </p>
*
* @return NULL if src is only whitespace (SP, TB, CR, LF,
* plus Unicode whitespace), otherwise original string.
*/
public final static String StringNotWS( char[] src, int ofs, int len){
for (int cc = ofs, clen = (ofs+len); cc < clen; cc++){
switch(src[cc]){
case 0x0009:
case 0x000A:
case 0x000B:
case 0x000C:
case 0x000D:
case 0x0020:
case 0x0085:
case 0x1680:
case 0x180E:
case 0x2000:
case 0x2001:
case 0x2002:
case 0x2003:
case 0x2004:
case 0x2005:
case 0x2006:
case 0x2007:
case 0x2008:
case 0x2009:
case 0x200A:
case 0x2028:
case 0x2029:
case 0x202F:
case 0x205F:
case 0x3000:
break;
default:
/*
* At the first non-whitespace character, return
* the string verbatum.
*/
return new String(src,ofs,len);
}
}
/*
* Just whitespace, return null.
*/
return null;
}
}