summaryrefslogtreecommitdiffstats
path: root/libjava/classpath/gnu/xml
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/gnu/xml')
-rw-r--r--libjava/classpath/gnu/xml/aelfred2/SAXDriver.java15
-rw-r--r--libjava/classpath/gnu/xml/aelfred2/XmlParser.java3
-rw-r--r--libjava/classpath/gnu/xml/dom/Consumer.java16
-rw-r--r--libjava/classpath/gnu/xml/dom/DomDocument.java25
-rw-r--r--libjava/classpath/gnu/xml/dom/DomElement.java33
-rw-r--r--libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java2
-rw-r--r--libjava/classpath/gnu/xml/dom/DomNode.java215
-rw-r--r--libjava/classpath/gnu/xml/dom/ls/DomLSParser.java1
-rw-r--r--libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java182
-rw-r--r--libjava/classpath/gnu/xml/pipeline/DomConsumer.java17
-rw-r--r--libjava/classpath/gnu/xml/pipeline/EventFilter.java15
-rw-r--r--libjava/classpath/gnu/xml/stream/BufferedReader.java198
-rw-r--r--libjava/classpath/gnu/xml/stream/CRLFReader.java180
-rw-r--r--libjava/classpath/gnu/xml/stream/SAXParser.java966
-rw-r--r--libjava/classpath/gnu/xml/stream/SAXParserFactory.java104
-rw-r--r--libjava/classpath/gnu/xml/stream/UnicodeReader.java201
-rw-r--r--libjava/classpath/gnu/xml/stream/XIncludeFilter.java932
-rw-r--r--libjava/classpath/gnu/xml/stream/XMLInputFactoryImpl.java75
-rw-r--r--libjava/classpath/gnu/xml/stream/XMLParser.java5266
-rw-r--r--libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java2
-rw-r--r--libjava/classpath/gnu/xml/transform/AttributeNode.java54
-rw-r--r--libjava/classpath/gnu/xml/transform/Bindings.java22
-rw-r--r--libjava/classpath/gnu/xml/transform/ElementAvailableFunction.java19
-rw-r--r--libjava/classpath/gnu/xml/transform/ElementNode.java157
-rw-r--r--libjava/classpath/gnu/xml/transform/FunctionAvailableFunction.java28
-rw-r--r--libjava/classpath/gnu/xml/transform/LiteralNode.java64
-rw-r--r--libjava/classpath/gnu/xml/transform/MessageNode.java23
-rw-r--r--libjava/classpath/gnu/xml/transform/NamespaceProxy.java77
-rw-r--r--libjava/classpath/gnu/xml/transform/StreamSerializer.java474
-rw-r--r--libjava/classpath/gnu/xml/transform/StrippingInstruction.java (renamed from libjava/classpath/gnu/xml/aelfred2/ContentHandler2.java)44
-rw-r--r--libjava/classpath/gnu/xml/transform/Stylesheet.java375
-rw-r--r--libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java49
-rw-r--r--libjava/classpath/gnu/xml/transform/TransformerImpl.java240
-rw-r--r--libjava/classpath/gnu/xml/transform/ValueOfNode.java56
-rw-r--r--libjava/classpath/gnu/xml/xpath/Expr.java45
-rw-r--r--libjava/classpath/gnu/xml/xpath/LocalNameFunction.java6
-rw-r--r--libjava/classpath/gnu/xml/xpath/NameFunction.java6
-rw-r--r--libjava/classpath/gnu/xml/xpath/NameTest.java39
-rw-r--r--libjava/classpath/gnu/xml/xpath/NamespaceTest.java26
-rw-r--r--libjava/classpath/gnu/xml/xpath/NamespaceUriFunction.java6
-rw-r--r--libjava/classpath/gnu/xml/xpath/NodeTypeTest.java20
-rw-r--r--libjava/classpath/gnu/xml/xpath/Selector.java157
-rw-r--r--libjava/classpath/gnu/xml/xpath/SubstringFunction.java21
43 files changed, 9217 insertions, 1239 deletions
diff --git a/libjava/classpath/gnu/xml/aelfred2/SAXDriver.java b/libjava/classpath/gnu/xml/aelfred2/SAXDriver.java
index 6864ff65971..e7c4d5a3f64 100644
--- a/libjava/classpath/gnu/xml/aelfred2/SAXDriver.java
+++ b/libjava/classpath/gnu/xml/aelfred2/SAXDriver.java
@@ -655,21 +655,6 @@ final public class SAXDriver
attributesList.clear();
}
- void xmlDecl(String version,
- String encoding,
- boolean standalone,
- String inputEncoding)
- throws SAXException
- {
- if (contentHandler instanceof ContentHandler2)
- {
- ((ContentHandler2) contentHandler).xmlDecl(version,
- encoding,
- standalone,
- inputEncoding);
- }
- }
-
void skippedEntity(String name)
throws SAXException
{
diff --git a/libjava/classpath/gnu/xml/aelfred2/XmlParser.java b/libjava/classpath/gnu/xml/aelfred2/XmlParser.java
index f2abb889666..ab2ed16f946 100644
--- a/libjava/classpath/gnu/xml/aelfred2/XmlParser.java
+++ b/libjava/classpath/gnu/xml/aelfred2/XmlParser.java
@@ -841,9 +841,6 @@ final class XmlParser
{
inputEncoding = encodingName;
}
- handler.xmlDecl(version, encodingName, docIsStandalone,
- inputEncoding);
-
return encodingName;
}
diff --git a/libjava/classpath/gnu/xml/dom/Consumer.java b/libjava/classpath/gnu/xml/dom/Consumer.java
index f99e221e998..026e2754ef9 100644
--- a/libjava/classpath/gnu/xml/dom/Consumer.java
+++ b/libjava/classpath/gnu/xml/dom/Consumer.java
@@ -301,22 +301,6 @@ public class Consumer extends DomConsumer
doc.setBuilding(true);
}
- /**
- * Required by DOM Level 3 to report document parameters
- */
- public void xmlDecl(String version,
- String encoding,
- boolean standalone,
- String inputEncoding)
- throws SAXException
- {
- super.xmlDecl(version, encoding, standalone, inputEncoding);
-
- DomDocument doc = (DomDocument) getDocument();
- doc.setXmlEncoding(encoding);
- doc.setInputEncoding(inputEncoding);
- }
-
public void endDocument ()
throws SAXException
{
diff --git a/libjava/classpath/gnu/xml/dom/DomDocument.java b/libjava/classpath/gnu/xml/dom/DomDocument.java
index 29b8dc72e53..900d03ac3dc 100644
--- a/libjava/classpath/gnu/xml/dom/DomDocument.java
+++ b/libjava/classpath/gnu/xml/dom/DomDocument.java
@@ -1313,6 +1313,31 @@ public class DomDocument
return config;
}
+ public boolean isEqualNode(Node arg)
+ {
+ if (!super.isEqualNode(arg))
+ return false;
+ Document d = (Document) arg;
+ String dversion = d.getXmlVersion();
+ if (dversion == null || !dversion.equals(version))
+ return false;
+ boolean dstandalone = d.getXmlStandalone();
+ if (dstandalone != standalone)
+ return false;
+ String dencoding = d.getXmlEncoding();
+ if (dencoding == null || dencoding.equalsIgnoreCase("UTF-8"))
+ {
+ if (encoding != null && !encoding.equalsIgnoreCase("UTF-8"))
+ return false;
+ }
+ else
+ {
+ if (!dencoding.equals(encoding))
+ return false;
+ }
+ return true;
+ }
+
public void normalizeDocument()
{
boolean save = building;
diff --git a/libjava/classpath/gnu/xml/dom/DomElement.java b/libjava/classpath/gnu/xml/dom/DomElement.java
index 34509f647bc..f55b084cc94 100644
--- a/libjava/classpath/gnu/xml/dom/DomElement.java
+++ b/libjava/classpath/gnu/xml/dom/DomElement.java
@@ -519,5 +519,38 @@ public class DomElement
Attr attr = (Attr) attrs.getNamedItemNS(namespaceURI, localName);
setIdAttributeNode(attr, isId);
}
+
+ public boolean isEqualNode(Node arg)
+ {
+ if (!super.isEqualNode(arg))
+ return false;
+ getAttributes();
+ NamedNodeMap argAttrs = arg.getAttributes();
+ int len = argAttrs.getLength();
+ if (argAttrs == null || (len != attributes.length))
+ return false;
+ for (int i = 0; i < len; i++)
+ {
+ Node argCtx = argAttrs.item(i);
+ // Don't compare namespace nodes
+ if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI
+ .equals(argCtx.getNamespaceURI()))
+ continue;
+ // Find corresponding attribute node
+ DomNode ctx = attributes.first;
+ for (; ctx != null; ctx = ctx.next)
+ {
+ if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI
+ .equals(ctx.getNamespaceURI()))
+ continue;
+ if (!ctx.isEqualNode(argCtx))
+ continue;
+ break;
+ }
+ if (ctx == null)
+ return false; // not found
+ }
+ return true;
+ }
}
diff --git a/libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java b/libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java
index 6f224029ac3..e3f08e4b4b7 100644
--- a/libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java
+++ b/libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java
@@ -319,7 +319,7 @@ public class DomNamedNodeMap
if (ns)
{
String tln = ctx.getLocalName();
- if (tln.equals(name))
+ if (name != null && name.equals(tln))
{
String tu = ctx.getNamespaceURI();
if ((tu == null && uri == null) ||
diff --git a/libjava/classpath/gnu/xml/dom/DomNode.java b/libjava/classpath/gnu/xml/dom/DomNode.java
index 3f29fb1283d..93f7c6f64f3 100644
--- a/libjava/classpath/gnu/xml/dom/DomNode.java
+++ b/libjava/classpath/gnu/xml/dom/DomNode.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.xml.dom;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
@@ -149,7 +150,7 @@ public abstract class DomNode
boolean readonly;
// event registrations
- private ListenerRecord[] listeners;
+ private HashSet listeners;
private int nListeners;
// DOM Level 3 userData dictionary.
@@ -167,19 +168,6 @@ public abstract class DomNode
*/
public void compact()
{
- if (listeners != null && listeners.length != nListeners)
- {
- if (nListeners == 0)
- {
- listeners = null;
- }
- else
- {
- ListenerRecord[] l = new ListenerRecord[nListeners];
- System.arraycopy(listeners, 0, l, 0, nListeners);
- listeners = l;
- }
- }
}
/**
@@ -201,6 +189,7 @@ public abstract class DomNode
}
}
this.owner = owner;
+ this.listeners = new HashSet();
}
@@ -372,6 +361,16 @@ public abstract class DomNode
return;
}
break;
+ case DOCUMENT_TYPE_NODE:
+ if (!owner.building)
+ break;
+ switch (childNodeType)
+ {
+ case COMMENT_NODE:
+ case PROCESSING_INSTRUCTION_NODE:
+ return;
+ }
+ break;
}
if (owner.checkingWellformedness)
{
@@ -960,12 +959,6 @@ public abstract class DomNode
*/
public void trimToSize()
{
- if (listeners != null && listeners.length != nListeners)
- {
- ListenerRecord[] newKids = new ListenerRecord[length];
- System.arraycopy(listeners, 0, newKids, 0, nListeners);
- listeners = newKids;
- }
}
/**
@@ -1175,7 +1168,7 @@ public abstract class DomNode
node.next = null;
node.readonly = false;
- node.listeners = null;
+ node.listeners = new HashSet();
node.nListeners = 0;
return node;
@@ -1264,16 +1257,17 @@ public abstract class DomNode
elementName = name;
matchAnyURI = "*".equals(uri);
matchAnyName = "*".equals(name);
-
+
DomNode.this.addEventListener("DOMNodeInserted", this, true);
DomNode.this.addEventListener("DOMNodeRemoved", this, true);
}
void detach()
{
- current.detach();
+ if (current != null)
+ current.detach();
current = null;
-
+
DomNode.this.removeEventListener("DOMNodeInserted", this, true);
DomNode.this.removeEventListener("DOMNodeRemoved", this, true);
}
@@ -1336,6 +1330,8 @@ public abstract class DomNode
return;
}
+ if (current != null)
+ current.detach();
current = null;
}
@@ -1354,6 +1350,7 @@ public abstract class DomNode
lastIndex--;
}
Node ret = current.previousNode ();
+ current.detach();
current = null;
return ret;
}
@@ -1361,9 +1358,11 @@ public abstract class DomNode
// somewhere after last node
while (++lastIndex != index)
current.nextNode ();
- Node ret = current.nextNode ();
- current = null;
- return ret;
+
+ Node ret = current.nextNode ();
+ current.detach();
+ current = null;
+ return ret;
}
public int getLength()
@@ -1375,7 +1374,7 @@ public abstract class DomNode
{
retval++;
}
- current = null;
+ iter.detach();
return retval;
}
@@ -1403,13 +1402,18 @@ public abstract class DomNode
this.useCapture = useCapture;
}
- boolean equals(ListenerRecord rec)
+ public boolean equals(Object o)
{
+ ListenerRecord rec = (ListenerRecord)o;
return listener == rec.listener
&& useCapture == rec.useCapture
&& type == rec.type;
}
+ public int hashCode()
+ {
+ return listener.hashCode() ^ type.hashCode();
+ }
}
/**
@@ -1464,30 +1468,12 @@ public abstract class DomNode
EventListener listener,
boolean useCapture)
{
- if (listeners == null)
- {
- listeners = new ListenerRecord[1];
- }
- else if (nListeners == listeners.length)
- {
- ListenerRecord[] newListeners =
- new ListenerRecord[listeners.length + NKIDS_DELTA];
- System.arraycopy(listeners, 0, newListeners, 0, nListeners);
- listeners = newListeners;
- }
-
// prune duplicates
ListenerRecord record;
record = new ListenerRecord(type, listener, useCapture);
- for (int i = 0; i < nListeners; i++)
- {
- if (record.equals(listeners[i]))
- {
- return;
- }
- }
- listeners [nListeners++] = record;
+ listeners.add(record);
+ nListeners = listeners.size();
}
// XXX this exception should be discarded from DOM
@@ -1672,11 +1658,14 @@ public abstract class DomNode
ListenerRecord[] notificationSet)
{
int count = 0;
+ Iterator iter;
+
+ iter = current.listeners.iterator();
// do any of this set of listeners get notified?
- for (int i = 0; i < current.nListeners; i++)
+ while (iter.hasNext())
{
- ListenerRecord rec = current.listeners[i];
+ ListenerRecord rec = (ListenerRecord)iter.next();
if (rec.useCapture != capture)
{
@@ -1697,6 +1686,7 @@ public abstract class DomNode
}
notificationSet[count++] = rec;
}
+ iter = null;
// Notify just those listeners
e.currentNode = current;
@@ -1704,18 +1694,21 @@ public abstract class DomNode
{
try
{
+ iter = current.listeners.iterator();
// Late in the DOM CR process (3rd or 4th CR?) the
// removeEventListener spec became asymmetric with respect
// to addEventListener ... effect is now immediate.
- for (int j = 0; j < current.nListeners; j++)
+ while (iter.hasNext())
{
- if (current.listeners[j].equals(notificationSet[i]))
+ ListenerRecord rec = (ListenerRecord)iter.next();
+
+ if (rec.equals(notificationSet[i]))
{
notificationSet[i].listener.handleEvent(e);
break;
}
}
-
+ iter = null;
}
catch (Exception x)
{
@@ -1733,36 +1726,8 @@ public abstract class DomNode
EventListener listener,
boolean useCapture)
{
- for (int i = 0; i < nListeners; i++)
- {
- if (listeners[i].listener != listener)
- {
- continue;
- }
- if (listeners[i].useCapture != useCapture)
- {
- continue;
- }
- if (!listeners[i].type.equals(type))
- {
- continue;
- }
-
- if (nListeners == 1)
- {
- listeners = null;
- nListeners = 0;
- }
- else
- {
- for (int j = i + 1; j < nListeners; j++)
- {
- listeners[i++] = listeners[j++];
- }
- listeners[--nListeners] = null;
- }
- break;
- }
+ listeners.remove(new ListenerRecord(type, listener, useCapture));
+ nListeners = listeners.size();
// no exceptions reported
}
@@ -1779,10 +1744,15 @@ public abstract class DomNode
readonly = false;
for (DomNode ctx = first; ctx != null; ctx = ctx.next)
{
+ boolean saved2 = ctx.readonly;
+ ctx.readonly = false;
switch (ctx.nodeType)
{
case TEXT_NODE:
- while (ctx.next != null && ctx.next.nodeType == TEXT_NODE)
+ case CDATA_SECTION_NODE:
+ while (ctx.next != null &&
+ (ctx.next.nodeType == TEXT_NODE ||
+ ctx.next.nodeType == CDATA_SECTION_NODE))
{
Text text = (Text) ctx;
text.appendData(ctx.next.getNodeValue());
@@ -1794,7 +1764,11 @@ public abstract class DomNode
int len = attrs.getLength();
for (int i = 0; i < len; i++)
{
- attrs.item(i).normalize();
+ DomNode attr = (DomNode) attrs.item(i);
+ boolean saved3 = attr.readonly;
+ attr.readonly = false;
+ attr.normalize();
+ attr.readonly = saved3;
}
// Fall through
case DOCUMENT_NODE:
@@ -1804,6 +1778,7 @@ public abstract class DomNode
ctx.normalize();
break;
}
+ ctx.readonly = saved2;
}
readonly = saved;
}
@@ -2017,39 +1992,56 @@ public abstract class DomNode
public boolean isEqualNode(Node arg)
{
if (this == arg)
- {
- return true;
- }
+ return true;
if (arg == null)
+ return false;
+ if (nodeType != arg.getNodeType())
+ return false;
+ switch (nodeType)
{
- return false;
- }
- if (nodeType != arg.getNodeType() ||
- !equal(getNodeName(), arg.getNodeName()) ||
- !equal(getLocalName(), arg.getLocalName()) ||
- !equal(getNamespaceURI(), arg.getNamespaceURI()) ||
- !equal(getPrefix(), arg.getPrefix()) ||
- !equal(getNodeValue(), arg.getNodeValue()))
- {
- return false;
+ case ELEMENT_NODE:
+ case ATTRIBUTE_NODE:
+ if (!equal(getLocalName(), arg.getLocalName()) ||
+ !equal(getNamespaceURI(), arg.getNamespaceURI()))
+ return false;
+ break;
+ case PROCESSING_INSTRUCTION_NODE:
+ if (!equal(getNodeName(), arg.getNodeName()) ||
+ !equal(getNodeValue(), arg.getNodeValue()))
+ return false;
+ break;
+ case COMMENT_NODE:
+ case TEXT_NODE:
+ case CDATA_SECTION_NODE:
+ if (!equal(getNodeValue(), arg.getNodeValue()))
+ return false;
+ break;
}
// Children
Node argCtx = arg.getFirstChild();
getFirstChild(); // because of DomAttr lazy children
- for (DomNode ctx = first; ctx != null; ctx = ctx.next)
+ DomNode ctx = first;
+ for (; ctx != null && argCtx != null; ctx = ctx.next)
{
- if (!ctx.isEqualNode(argCtx))
+ if (nodeType == DOCUMENT_NODE)
{
- return false;
+ // Ignore whitespace outside document element
+ while (ctx != null && ctx.nodeType == TEXT_NODE)
+ ctx = ctx.next;
+ while (argCtx != null && ctx.getNodeType() == TEXT_NODE)
+ argCtx = argCtx.getNextSibling();
+ if (ctx == null && argCtx != null)
+ return false;
+ else if (argCtx == null && ctx != null)
+ return false;
}
+ if (!ctx.isEqualNode(argCtx))
+ return false;
argCtx = argCtx.getNextSibling();
}
- if (argCtx != null)
- {
- return false;
- }
+ if (ctx != null || argCtx != null)
+ return false;
- // TODO Attr NamedNodeMap
// TODO DocumentType
return true;
}
@@ -2185,5 +2177,14 @@ public abstract class DomNode
}
}
+ public void list(java.io.PrintStream out, int indent)
+ {
+ for (int i = 0; i < indent; i++)
+ out.print(" ");
+ out.println(toString());
+ for (DomNode ctx = first; ctx != null; ctx = ctx.next)
+ ctx.list(out, indent + 1);
+ }
+
}
diff --git a/libjava/classpath/gnu/xml/dom/ls/DomLSParser.java b/libjava/classpath/gnu/xml/dom/ls/DomLSParser.java
index eb7c1c49f3a..7ac4cc749fc 100644
--- a/libjava/classpath/gnu/xml/dom/ls/DomLSParser.java
+++ b/libjava/classpath/gnu/xml/dom/ls/DomLSParser.java
@@ -260,6 +260,7 @@ public class DomLSParser
eventSink.coalescing = coalescing;
// get and configure reader
XMLReader reader = getXMLReader();
+ eventSink.reader = reader;
try
{
reader.setContentHandler(eventSink);
diff --git a/libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java b/libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java
index a850460b1e2..aad5ac76e70 100644
--- a/libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java
+++ b/libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java
@@ -37,6 +37,7 @@ exception statement from your version. */
package gnu.xml.dom.ls;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -45,20 +46,26 @@ import org.w3c.dom.Attr;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.Entity;
+import org.w3c.dom.EntityReference;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
import org.xml.sax.DTDHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.XMLReader;
import org.xml.sax.ext.Attributes2;
import org.xml.sax.ext.DeclHandler;
import org.xml.sax.ext.LexicalHandler;
-import gnu.xml.aelfred2.ContentHandler2;
+import org.xml.sax.ext.Locator2;
import gnu.xml.dom.DomAttr;
import gnu.xml.dom.DomDocument;
import gnu.xml.dom.DomDoctype;
+import gnu.xml.dom.DomNode;
/**
* A SAX content and lexical handler used to construct a DOM document.
@@ -66,17 +73,28 @@ import gnu.xml.dom.DomDoctype;
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
class SAXEventSink
- implements ContentHandler2, LexicalHandler, DTDHandler, DeclHandler
+ implements ContentHandler, LexicalHandler, DTDHandler, DeclHandler
{
private static final String XMLNS_URI = XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
private static final String XMLNS_PREFIX = XMLConstants.XMLNS_ATTRIBUTE;
+ private static final HashSet PREDEFINED_ENTITIES = new HashSet();
+ static
+ {
+ PREDEFINED_ENTITIES.add("amp");
+ PREDEFINED_ENTITIES.add("lt");
+ PREDEFINED_ENTITIES.add("gt");
+ PREDEFINED_ENTITIES.add("quot");
+ PREDEFINED_ENTITIES.add("apos");
+ }
boolean namespaceAware;
boolean ignoreWhitespace;
boolean expandEntityReferences;
boolean ignoreComments;
boolean coalescing;
+
+ XMLReader reader; // reference back to the parser to get features
DomDocument doc; // document being constructed
Node ctx; // current context (parent node)
@@ -110,20 +128,42 @@ class SAXEventSink
doc.setStrictErrorChecking(false);
doc.setBuilding(true);
ctx = doc;
- }
- public void xmlDecl(String version, String encoding, boolean standalone,
- String inputEncoding)
- throws SAXException
- {
- if (interrupted)
+ final String FEATURES = "http://xml.org/sax/features/";
+ final String PROPERTIES = "http://xml.org/sax/properties/";
+ final String GNU_PROPERTIES = "http://gnu.org/sax/properties/";
+
+ boolean standalone = reader.getFeature(FEATURES + "is-standalone");
+ doc.setXmlStandalone(standalone);
+ try
+ {
+ String version = (String) reader.getProperty(PROPERTIES +
+ "document-xml-version");
+ doc.setXmlVersion(version);
+ }
+ catch (SAXNotRecognizedException e)
+ {
+ }
+ catch (SAXNotSupportedException e)
+ {
+ }
+ if (locator != null && locator instanceof Locator2)
+ {
+ String encoding = ((Locator2) locator).getEncoding();
+ doc.setInputEncoding(encoding);
+ }
+ try
+ {
+ String encoding = (String) reader.getProperty(GNU_PROPERTIES +
+ "document-xml-encoding");
+ doc.setXmlEncoding(encoding);
+ }
+ catch (SAXNotRecognizedException e)
+ {
+ }
+ catch (SAXNotSupportedException e)
{
- return;
}
- doc.setXmlVersion(version);
- doc.setXmlEncoding(encoding);
- doc.setXmlStandalone(standalone);
- doc.setInputEncoding(inputEncoding);
}
public void endDocument()
@@ -265,7 +305,7 @@ class SAXEventSink
public void characters(char[] c, int off, int len)
throws SAXException
{
- if (interrupted)
+ if (interrupted || len < 1)
{
return;
}
@@ -301,11 +341,8 @@ class SAXEventSink
{
return;
}
- if (!inDTD)
- {
- Node pi = createProcessingInstruction(target, data);
- ctx.appendChild(pi);
- }
+ Node pi = createProcessingInstruction(target, data);
+ ctx.appendChild(pi);
}
protected Node createProcessingInstruction(String target, String data)
@@ -354,6 +391,8 @@ class SAXEventSink
public void startEntity(String name)
throws SAXException
{
+ if (interrupted)
+ return;
DocumentType doctype = doc.getDoctype();
if (doctype == null)
{
@@ -361,19 +400,9 @@ class SAXEventSink
"reference to entity in undeclared doctype");
}
if ("[dtd]".equals(name) || name.charAt(0) == '%')
- {
- // Ignore DTD and parameter entities
- ctx = doctype;
- return;
- }
- if ("lt".equals(name) ||
- "gt".equals(name) ||
- "amp".equals(name) ||
- "apos".equals(name) ||
- "quot".equals(name))
- {
- return;
- }
+ return;
+ if (PREDEFINED_ENTITIES.contains(name))
+ return;
// Get entity
NamedNodeMap entities = doctype.getEntities();
Entity entity = (Entity) entities.getNamedItem(name);
@@ -382,59 +411,47 @@ class SAXEventSink
throw new SAXException("SAX parser error: " +
"reference to undeclared entity: " + name);
}
- pushEntity(entity);
+ EntityReference ref = doc.createEntityReference(name);
+ // DomDocument populates with the entity replacement text, remove this
+ Node child = ref.getFirstChild();
+ while (child != null)
+ {
+ Node nextChild = child.getNextSibling();
+ ref.removeChild(child);
+ child = nextChild;
+ }
+ ctx.appendChild(ref);
+ ctx = ref;
}
public void endEntity(String name)
throws SAXException
{
+ if (interrupted)
+ return;
if ("[dtd]".equals(name) || name.charAt(0) == '%')
- {
- // Ignore DTD and parameter entities
- return;
- }
- if ("lt".equals(name) ||
- "gt".equals(name) ||
- "amp".equals(name) ||
- "apos".equals(name) ||
- "quot".equals(name))
- {
- return;
- }
- // Get entity
- Entity entity = popEntity();
- // TODO resolve external entities to ensure that entity has content
+ return;
+ if (PREDEFINED_ENTITIES.contains(name))
+ return;
+ // Get entity reference
+ EntityReference ref = (EntityReference) ctx;
+ if (!ref.getNodeName().equals(name))
+ throw new SAXException("expecting end of "+ref.getNodeName()+" entity");
+ ctx = ctx.getParentNode();
+ if (ref instanceof DomNode)
+ ((DomNode) ref).makeReadonly();
if (expandEntityReferences)
{
- // Get entity content
- for (Node child = entity.getFirstChild(); child != null;
- child = child.getNextSibling())
+ // Move entity content from reference node onto context
+ Node child = ref.getFirstChild();
+ while (child != null)
{
+ Node nextChild = child.getNextSibling();
ctx.appendChild(child);
+ child = nextChild;
}
+ ctx.removeChild(ref);
}
- else
- {
- Node entityReference = doc.createEntityReference(name);
- ctx.appendChild(entityReference);
- }
- }
-
- void pushEntity(Node entity)
- {
- if (entityCtx == null)
- {
- entityCtx = new LinkedList();
- }
- entityCtx.addLast(ctx);
- ctx = entity;
- }
-
- Entity popEntity()
- {
- Entity ret = (Entity) ctx;
- ctx = (Node) entityCtx.removeLast();
- return ret;
}
public void startCDATA()
@@ -456,11 +473,8 @@ class SAXEventSink
{
return;
}
- if (!inDTD)
- {
- Node comment = createComment(c, off, len);
- ctx.appendChild(comment);
- }
+ Node comment = createComment(c, off, len);
+ ctx.appendChild(comment);
}
protected Node createComment(char[] c, int off, int len)
@@ -477,6 +491,8 @@ class SAXEventSink
{
return;
}
+ if (!inDTD)
+ throw new SAXException("notation decl outside DTD");
DomDoctype doctype = (DomDoctype) ctx;
doctype.declareNotation(name, publicId, systemId);
}
@@ -489,6 +505,8 @@ class SAXEventSink
{
return;
}
+ if (!inDTD)
+ throw new SAXException("unparsed entity decl outside DTD");
DomDoctype doctype = (DomDoctype) ctx;
Entity entity = doctype.declareEntity(name, publicId, systemId,
notationName);
@@ -503,6 +521,8 @@ class SAXEventSink
{
return;
}
+ if (!inDTD)
+ throw new SAXException("element decl outside DTD");
// Ignore fake element declarations generated by ValidationConsumer.
// If an element is not really declared in the DTD it will not be
// declared in the document model.
@@ -522,6 +542,8 @@ class SAXEventSink
{
return;
}
+ if (!inDTD)
+ throw new SAXException("attribute decl outside DTD");
DomDoctype doctype = (DomDoctype) ctx;
doctype.attributeDecl(eName, aName, type, mode, value);
}
@@ -533,6 +555,8 @@ class SAXEventSink
{
return;
}
+ if (!inDTD)
+ throw new SAXException("internal entity decl outside DTD");
DomDoctype doctype = (DomDoctype) ctx;
Entity entity = doctype.declareEntity(name, null, null, null);
if (entity != null)
@@ -549,6 +573,8 @@ class SAXEventSink
{
return;
}
+ if (!inDTD)
+ throw new SAXException("external entity decl outside DTD");
DomDoctype doctype = (DomDoctype) ctx;
Entity entity = doctype.declareEntity(name, publicId, systemId, null);
}
diff --git a/libjava/classpath/gnu/xml/pipeline/DomConsumer.java b/libjava/classpath/gnu/xml/pipeline/DomConsumer.java
index 389e02bb387..bdbf9281880 100644
--- a/libjava/classpath/gnu/xml/pipeline/DomConsumer.java
+++ b/libjava/classpath/gnu/xml/pipeline/DomConsumer.java
@@ -37,7 +37,6 @@ exception statement from your version. */
package gnu.xml.pipeline;
-import gnu.xml.aelfred2.ContentHandler2;
import gnu.xml.util.DomParser;
import org.xml.sax.Attributes;
@@ -330,7 +329,7 @@ public class DomConsumer implements EventConsumer
* accepted illegal input data). </p>
*/
public static class Handler
- implements ContentHandler2, LexicalHandler,
+ implements ContentHandler, LexicalHandler,
DTDHandler, DeclHandler
{
protected DomConsumer consumer;
@@ -430,20 +429,6 @@ public class DomConsumer implements EventConsumer
top = document;
}
- // ContentHandler2
- public void xmlDecl(String version,
- String encoding,
- boolean standalone,
- String inputEncoding)
- throws SAXException
- {
- if (document != null)
- {
- document.setXmlVersion(version);
- document.setXmlStandalone(standalone);
- }
- }
-
// SAX1
public void endDocument ()
throws SAXException
diff --git a/libjava/classpath/gnu/xml/pipeline/EventFilter.java b/libjava/classpath/gnu/xml/pipeline/EventFilter.java
index 6600271718a..a14fb340f12 100644
--- a/libjava/classpath/gnu/xml/pipeline/EventFilter.java
+++ b/libjava/classpath/gnu/xml/pipeline/EventFilter.java
@@ -44,8 +44,6 @@ import org.xml.sax.*;
import org.xml.sax.ext.*;
import org.xml.sax.helpers.XMLFilterImpl;
-import gnu.xml.aelfred2.ContentHandler2;
-
/**
* A customizable event consumer, used to assemble various kinds of filters
* using SAX handlers and an optional second consumer. It can be constructed
@@ -138,7 +136,7 @@ import gnu.xml.aelfred2.ContentHandler2;
* @author David Brownell
*/
public class EventFilter
- implements EventConsumer, ContentHandler2, DTDHandler,
+ implements EventConsumer, ContentHandler, DTDHandler,
LexicalHandler, DeclHandler
{
// SAX handlers
@@ -600,17 +598,6 @@ public class EventFilter
docNext.startDocument ();
}
- public void xmlDecl(String version, String encoding, boolean standalone,
- String inputEncoding)
- throws SAXException
- {
- if (docNext != null && docNext instanceof ContentHandler2)
- {
- ((ContentHandler2) docNext).xmlDecl(version, encoding, standalone,
- inputEncoding);
- }
- }
-
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void skippedEntity (String name) throws SAXException
{
diff --git a/libjava/classpath/gnu/xml/stream/BufferedReader.java b/libjava/classpath/gnu/xml/stream/BufferedReader.java
new file mode 100644
index 00000000000..f8287e823fd
--- /dev/null
+++ b/libjava/classpath/gnu/xml/stream/BufferedReader.java
@@ -0,0 +1,198 @@
+/* BufferedReader.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath 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, or (at your option)
+any later version.
+
+GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.stream;
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * A mark-capable buffered reader.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class BufferedReader
+ extends Reader
+{
+
+ static final int DEFAULT_BUFFER_SIZE = 4096;
+
+ final Reader in;
+ char[] buf;
+ int pos, count, markpos, marklimit, bufferSize;
+
+ BufferedReader(Reader in)
+ {
+ this(in, DEFAULT_BUFFER_SIZE);
+ }
+
+ BufferedReader(Reader in, int bufferSize)
+ {
+ if (bufferSize < 1)
+ throw new IllegalArgumentException();
+ this.in = in;
+ this.bufferSize = bufferSize;
+ buf = new char[bufferSize];
+ pos = count = bufferSize;
+ }
+
+ public void close()
+ throws IOException
+ {
+ buf = null;
+ pos = count = 0;
+ markpos = -1;
+ in.close();
+ }
+
+ public void mark(int readlimit)
+ throws IOException
+ {
+ marklimit = readlimit;
+ markpos = pos;
+ }
+
+ public boolean markSupported()
+ {
+ return true;
+ }
+
+ public int read()
+ throws IOException
+ {
+ if (pos >= count && !refill())
+ return -1;
+ return (int) buf[pos++];
+ }
+
+ public int read(char[] b)
+ throws IOException
+ {
+ return read(b, 0, b.length);
+ }
+
+ public int read(char[] b, int off, int len)
+ throws IOException
+ {
+ if (off < 0 || len < 0 || b.length - off < len)
+ throw new IndexOutOfBoundsException();
+
+ if (len == 0)
+ return 0;
+
+ if (pos >= count && !refill())
+ return -1;
+
+ int ret = Math.min(count - pos, len);
+ System.arraycopy(buf, pos, b, off, ret);
+ pos += ret;
+ off += ret;
+ len -= ret;
+
+ while (len > 0 && refill())
+ {
+ int remain = Math.min(count - pos, len);
+ System.arraycopy(buf, pos, b, off, remain);
+ pos += remain;
+ off += remain;
+ len -= remain;
+ ret += remain;
+ }
+
+ return ret;
+ }
+
+ public void reset()
+ throws IOException
+ {
+ if (markpos == -1)
+ throw new IOException(buf == null ? "Stream closed." : "Invalid mark.");
+ pos = markpos;
+ }
+
+ public long skip(long n)
+ throws IOException
+ {
+ if (buf == null)
+ throw new IOException("Stream closed.");
+ final long origN = n;
+ while (n > 0L)
+ {
+ if (pos >= count && !refill())
+ break;
+ int numread = (int) Math.min((long) (count - pos), n);
+ pos += numread;
+ n -= numread;
+ }
+ return origN - n;
+ }
+
+ private boolean refill()
+ throws IOException
+ {
+ if (buf == null)
+ throw new IOException("Stream closed.");
+
+ int markcount = count - markpos;
+ if (markpos == -1 || markcount >= marklimit)
+ {
+ markpos = -1;
+ pos = count = 0;
+ }
+ else
+ {
+ char[] newbuf = buf;
+ if (markpos < bufferSize)
+ {
+ newbuf = new char[count - markpos + bufferSize];
+ }
+ System.arraycopy(buf, markpos, newbuf, 0, markcount);
+ buf = newbuf;
+ count = markcount;
+ pos -= markpos;
+ markpos = 0;
+ }
+
+ int numread = in.read(buf, count, bufferSize);
+ if (numread <= 0)
+ return false;
+
+ count += numread;
+ return true;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/stream/CRLFReader.java b/libjava/classpath/gnu/xml/stream/CRLFReader.java
new file mode 100644
index 00000000000..1d214ce52c1
--- /dev/null
+++ b/libjava/classpath/gnu/xml/stream/CRLFReader.java
@@ -0,0 +1,180 @@
+/* CRLFReader.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath 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, or (at your option)
+any later version.
+
+GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.stream;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * Filtered reader that normalizes CRLF pairs into LFs.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class CRLFReader
+ extends Reader
+{
+
+ /**
+ * The CR octet.
+ */
+ public static final int CR = 13;
+
+ /**
+ * The LF octet.
+ */
+ public static final int LF = 10;
+
+ private boolean doReset;
+
+ protected Reader in;
+
+ /**
+ * Constructor.
+ */
+ protected CRLFReader(Reader in)
+ {
+ if (!in.markSupported())
+ in = new BufferedReader(in);
+ this.in = in;
+ }
+
+ public int read()
+ throws IOException
+ {
+ int c = in.read();
+ if (c == 13) // CR
+ {
+ in.mark(1);
+ int d = in.read();
+ if (d == 10) // LF
+ c = d;
+ else
+ in.reset();
+ }
+ return c;
+ }
+
+ public int read(char[] b)
+ throws IOException
+ {
+ return read(b, 0, b.length);
+ }
+
+ public int read(char[] b, int off, int len)
+ throws IOException
+ {
+ in.mark(len + 1);
+ int l = in.read(b, off, len);
+ if (l > 0)
+ {
+ int i = indexOfCRLF(b, off, l);
+ if (doReset)
+ {
+ in.reset();
+ if (i != -1)
+ {
+ l = in.read(b, off, (i + 1) - off); // read to CR
+ in.read(); // skip LF
+ b[i] = '\n'; // fix CR as LF
+ }
+ else
+ l = in.read(b, off, len); // CR(s) but no LF
+ }
+ }
+ return l;
+ }
+
+ public boolean markSupported()
+ {
+ return in.markSupported();
+ }
+
+ public void mark(int limit)
+ throws IOException
+ {
+ in.mark(limit);
+ }
+
+ public void reset()
+ throws IOException
+ {
+ in.reset();
+ }
+
+ public long skip(long n)
+ throws IOException
+ {
+ return in.skip(n);
+ }
+
+ public void close()
+ throws IOException
+ {
+ in.close();
+ }
+
+ private int indexOfCRLF(char[] b, int off, int len)
+ throws IOException
+ {
+ doReset = false;
+ int lm1 = len - 1;
+ for (int i = off; i < len; i++)
+ {
+ if (b[i] == '\r') // CR
+ {
+ int d;
+ if (i == lm1)
+ {
+ d = in.read();
+ doReset = true;
+ }
+ else
+ d = b[i + 1];
+ if (d == '\n') // LF
+ {
+ doReset = true;
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/stream/SAXParser.java b/libjava/classpath/gnu/xml/stream/SAXParser.java
new file mode 100644
index 00000000000..54c8b36244b
--- /dev/null
+++ b/libjava/classpath/gnu/xml/stream/SAXParser.java
@@ -0,0 +1,966 @@
+/* SAXParser.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath 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, or (at your option)
+any later version.
+
+GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.stream;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Reader;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.Map;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLReporter;
+import javax.xml.stream.XMLResolver;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.DTDHandler;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.Parser;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.ext.Attributes2;
+import org.xml.sax.ext.DeclHandler;
+import org.xml.sax.ext.EntityResolver2;
+import org.xml.sax.ext.LexicalHandler;
+import org.xml.sax.ext.Locator2;
+
+/**
+ * JAXP SAX parser using an underlying StAX parser.
+ * This parser supports the following additional SAX features and
+ * properties:
+ * <table>
+ * <tr><th colspan='4'>Features</th></tr>
+ * <tr><td>http://gnu.org/sax/features/xml-base</td>
+ * <td colspan='2'>read/write</td>
+ * <td>Indicates or sets whether XML Base processing is enabled</td></tr>
+ * <tr><th colspan='4'>Properties</th></tr>
+ * <tr><td>http://gnu.org/sax/properties/base-uri</td>
+ * <td>read-only</td><td>String</td>
+ * <td>Returns the base URI of the current event</td></tr>
+ * <tr><td>http://gnu.org/sax/properties/document-xml-encoding</td>
+ * <td>read-only</td><td>String</td>
+ * <td>Returns the encoding specified in the XML declaration</td></tr>
+ * </table>
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class SAXParser
+ extends javax.xml.parsers.SAXParser
+ implements XMLReader, Attributes2, Locator2, XMLReporter,
+ XMLParser.XMLResolver2
+{
+
+ ContentHandler contentHandler;
+ DeclHandler declHandler;
+ DTDHandler dtdHandler;
+ EntityResolver entityResolver;
+ ErrorHandler errorHandler;
+ LexicalHandler lexicalHandler;
+
+ boolean validating = false;
+ boolean namespaceAware = true;
+ boolean xIncludeAware = false;
+ boolean stringInterning = true;
+ boolean coalescing = true;
+ boolean replaceERefs = true;
+ boolean externalEntities = true;
+ boolean supportDTD = true;
+ boolean baseAware = true;
+
+ XMLParser parser;
+ XMLStreamReader reader;
+ String encoding;
+ String xmlVersion;
+ boolean xmlStandalone;
+ String xmlEncoding;
+ String baseURI;
+
+ public SAXParser()
+ {
+ }
+
+ SAXParser(boolean validating, boolean namespaceAware, boolean xIncludeAware)
+ {
+ this.validating = validating;
+ this.namespaceAware = namespaceAware;
+ this.xIncludeAware = xIncludeAware;
+ }
+
+ // -- SAXParser --
+
+ public Parser getParser()
+ throws SAXException
+ {
+ return null;
+ }
+
+ public XMLReader getXMLReader()
+ throws SAXException
+ {
+ return this;
+ }
+
+ public boolean isNamespaceAware()
+ {
+ return namespaceAware;
+ }
+
+ public boolean isValidating()
+ {
+ return validating;
+ }
+
+ public void setProperty(String name, Object value)
+ throws SAXNotRecognizedException, SAXNotSupportedException
+ {
+ if (parser != null)
+ throw new IllegalStateException("parsing in progress");
+ final String FEATURES = "http://xml.org/sax/features/";
+ final String PROPERTIES = "http://xml.org/sax/properties/";
+ final String GNU_FEATURES = "http://gnu.org/sax/features/";
+ if ((FEATURES + "namespaces").equals(name))
+ namespaceAware = Boolean.TRUE.equals(value);
+ else if ((FEATURES + "namespace-prefixes").equals(name))
+ {
+ // NOOP
+ }
+ else if ((FEATURES + "string-interning").equals(name))
+ stringInterning = Boolean.TRUE.equals(value);
+ else if ((FEATURES + "use-attributes2").equals(name))
+ {
+ // NOOP
+ }
+ else if ((FEATURES + "validation").equals(name))
+ validating = Boolean.TRUE.equals(value);
+ else if ((FEATURES + "external-general-entities").equals(name))
+ externalEntities = Boolean.TRUE.equals(value);
+ else if ((FEATURES + "external-parameter-entities").equals(name))
+ externalEntities = Boolean.TRUE.equals(value);
+ else if ((PROPERTIES + "declaration-handler").equals(name))
+ declHandler = (DeclHandler) value;
+ else if ((PROPERTIES + "lexical-handler").equals(name))
+ lexicalHandler = (LexicalHandler) value;
+ else if ((GNU_FEATURES + "xml-base").equals(name))
+ baseAware = Boolean.TRUE.equals(value);
+ else
+ throw new SAXNotSupportedException(name);
+ }
+
+ public Object getProperty(String name)
+ throws SAXNotRecognizedException, SAXNotSupportedException
+ {
+ final String FEATURES = "http://xml.org/sax/features/";
+ final String PROPERTIES = "http://xml.org/sax/properties/";
+ final String GNU_FEATURES = "http://gnu.org/sax/features/";
+ final String GNU_PROPERTIES = "http://gnu.org/sax/properties/";
+ if ((GNU_FEATURES + "base-uri").equals(name))
+ return baseURI;
+ if ((FEATURES + "is-standalone").equals(name))
+ return xmlStandalone ? Boolean.TRUE : Boolean.FALSE;
+ if ((FEATURES + "namespaces").equals(name))
+ return namespaceAware ? Boolean.TRUE : Boolean.FALSE;
+ if ((FEATURES + "namespace-prefixes").equals(name))
+ return Boolean.TRUE;
+ if ((FEATURES + "string-interning").equals(name))
+ return stringInterning ? Boolean.TRUE : Boolean.FALSE;
+ if ((FEATURES + "use-attributes2").equals(name))
+ return Boolean.TRUE;
+ if ((FEATURES + "use-locator2").equals(name))
+ return Boolean.TRUE;
+ if ((FEATURES + "use-entity-resolver2").equals(name))
+ return Boolean.FALSE;
+ if ((FEATURES + "validation").equals(name))
+ return validating ? Boolean.TRUE : Boolean.FALSE;
+ if ((FEATURES + "external-general-entities").equals(name))
+ return externalEntities ? Boolean.TRUE : Boolean.FALSE;
+ if ((FEATURES + "external-parameter-entities").equals(name))
+ return externalEntities ? Boolean.TRUE : Boolean.FALSE;
+ if ((FEATURES + "xml-1.1").equals(name))
+ return Boolean.TRUE;
+ if ((PROPERTIES + "declaration-handler").equals(name))
+ return declHandler;
+ if ((PROPERTIES + "document-xml-version").equals(name))
+ return xmlVersion;
+ if ((PROPERTIES + "lexical-handler").equals(name))
+ return lexicalHandler;
+ if ((GNU_FEATURES + "xml-base").equals(name))
+ return baseAware ? Boolean.TRUE : Boolean.FALSE;
+ if ((GNU_PROPERTIES + "document-xml-encoding").equals(name))
+ return xmlEncoding;
+ throw new SAXNotSupportedException(name);
+ }
+
+ public boolean isXIncludeAware()
+ {
+ return xIncludeAware;
+ }
+
+ public void reset()
+ {
+ parser = null;
+ encoding = null;
+ xmlVersion = null;
+ xmlStandalone = false;
+ }
+
+ // -- XMLReader --
+
+ public boolean getFeature(String name)
+ throws SAXNotRecognizedException, SAXNotSupportedException
+ {
+ Object ret = getProperty(name);
+ if (ret instanceof Boolean)
+ return ((Boolean) ret).booleanValue();
+ throw new SAXNotSupportedException(name);
+ }
+
+ public void setFeature(String name, boolean value)
+ throws SAXNotRecognizedException, SAXNotSupportedException
+ {
+ setProperty(name, value ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ public void setEntityResolver(EntityResolver resolver)
+ {
+ entityResolver = resolver;
+ }
+
+ public EntityResolver getEntityResolver()
+ {
+ return entityResolver;
+ }
+
+ public void setDTDHandler(DTDHandler handler)
+ {
+ dtdHandler = handler;
+ }
+
+ public DTDHandler getDTDHandler()
+ {
+ return dtdHandler;
+ }
+
+ public void setContentHandler(ContentHandler handler)
+ {
+ contentHandler = handler;
+ }
+
+ public ContentHandler getContentHandler()
+ {
+ return contentHandler;
+ }
+
+ public void setErrorHandler(ErrorHandler handler)
+ {
+ errorHandler = handler;
+ }
+
+ public ErrorHandler getErrorHandler()
+ {
+ return errorHandler;
+ }
+
+ public synchronized void parse(InputSource input)
+ throws IOException, SAXException
+ {
+ reset();
+ String systemId = input.getSystemId();
+ InputStream in = input.getByteStream();
+ boolean opened = false;
+ if (in != null)
+ parser = new XMLParser(in, systemId,
+ validating,
+ namespaceAware,
+ coalescing,
+ replaceERefs,
+ externalEntities,
+ supportDTD,
+ baseAware,
+ stringInterning,
+ this,
+ this);
+ else
+ {
+ Reader r = input.getCharacterStream();
+ if (r != null)
+ parser = new XMLParser(r, systemId,
+ validating,
+ namespaceAware,
+ coalescing,
+ replaceERefs,
+ externalEntities,
+ supportDTD,
+ baseAware,
+ stringInterning,
+ this,
+ this);
+ }
+ if (parser == null)
+ {
+ if (systemId == null)
+ throw new SAXException("No stream or system ID specified");
+ systemId = XMLParser.absolutize(null, systemId);
+ in = new URL(systemId).openStream();
+ opened = true;
+ parser = new XMLParser(in, systemId,
+ validating,
+ namespaceAware,
+ coalescing,
+ replaceERefs,
+ externalEntities,
+ supportDTD,
+ baseAware,
+ stringInterning,
+ this,
+ this);
+ }
+ reader = parser;
+ baseURI = systemId;
+
+ if (xIncludeAware)
+ reader = new XIncludeFilter(parser, systemId, namespaceAware,
+ validating, true);
+
+ if (contentHandler != null)
+ contentHandler.setDocumentLocator(this);
+ boolean startDocumentDone = false;
+ try
+ {
+ while (parser.hasNext())
+ {
+ int event = parser.next();
+ if (baseAware)
+ baseURI = parser.getXMLBase();
+ switch (event)
+ {
+ case XMLStreamConstants.CHARACTERS:
+ if (contentHandler != null)
+ {
+ char[] b = reader.getTextCharacters();
+ contentHandler.characters(b, 0, b.length);
+ }
+ break;
+ case XMLStreamConstants.SPACE:
+ if (contentHandler != null)
+ {
+ char[] b = reader.getTextCharacters();
+ if (isIgnorableWhitespace(parser, b, false))
+ contentHandler.ignorableWhitespace(b, 0, b.length);
+ else
+ contentHandler.characters(b, 0, b.length);
+ }
+ break;
+ case XMLStreamConstants.CDATA:
+ if (lexicalHandler != null)
+ lexicalHandler.startCDATA();
+ if (contentHandler != null)
+ {
+ char[] b = reader.getTextCharacters();
+ if (isIgnorableWhitespace(parser, b, true))
+ contentHandler.ignorableWhitespace(b, 0, b.length);
+ else
+ contentHandler.characters(b, 0, b.length);
+ }
+ if (lexicalHandler != null)
+ lexicalHandler.endCDATA();
+ break;
+ case XMLStreamConstants.START_ELEMENT:
+ if (contentHandler != null)
+ {
+ QName name = reader.getName();
+ String uri = name.getNamespaceURI();
+ String localName = name.getLocalPart();
+ String prefix = name.getPrefix();
+ String qName = localName;
+ if (!"".equals(prefix))
+ qName = prefix + ":" + localName;
+ if (!namespaceAware)
+ {
+ uri = "";
+ localName = "";
+ }
+ else
+ {
+ int nc = reader.getNamespaceCount();
+ for (int i = 0; i < nc; i++)
+ {
+ String nsuri = reader.getNamespaceURI(i);
+ String nsprefix = reader.getNamespacePrefix(i);
+ if ("xml".equals(nsprefix))
+ continue;
+ contentHandler.startPrefixMapping(nsprefix, nsuri);
+ }
+ }
+ contentHandler.startElement(uri, localName, qName, this);
+ }
+ break;
+ case XMLStreamConstants.END_ELEMENT:
+ if (contentHandler != null)
+ {
+ QName name = reader.getName();
+ String uri = name.getNamespaceURI();
+ String localName = name.getLocalPart();
+ String prefix = name.getPrefix();
+ String qName = localName;
+ if (!"".equals(prefix))
+ qName = prefix + ":" + localName;
+ if (!namespaceAware)
+ {
+ uri = "";
+ localName = "";
+ }
+ contentHandler.endElement(uri, localName, qName);
+ if (namespaceAware)
+ {
+ int nc = reader.getNamespaceCount();
+ for (int i = 0; i < nc; i++)
+ {
+ String nsprefix = reader.getNamespacePrefix(i);
+ if ("xml".equals(nsprefix))
+ continue;
+ contentHandler.endPrefixMapping(nsprefix);
+ }
+ }
+ }
+ break;
+ case XMLStreamConstants.COMMENT:
+ if (lexicalHandler != null)
+ {
+ char[] b = reader.getTextCharacters();
+ lexicalHandler.comment(b, 0, b.length);
+ }
+ break;
+ case XMLStreamConstants.PROCESSING_INSTRUCTION:
+ if (contentHandler != null)
+ {
+ String target = reader.getPITarget();
+ String data = reader.getPIData();
+ if (data == null)
+ data = "";
+ contentHandler.processingInstruction(target, data);
+ }
+ break;
+ case XMLStreamConstants.START_ENTITY:
+ if (lexicalHandler != null)
+ {
+ String name = reader.getText();
+ lexicalHandler.startEntity(name);
+ }
+ break;
+ case XMLStreamConstants.END_ENTITY:
+ if (lexicalHandler != null)
+ {
+ String name = reader.getText();
+ lexicalHandler.endEntity(name);
+ }
+ break;
+ case XMLStreamConstants.START_DOCUMENT:
+ encoding = reader.getEncoding();
+ xmlVersion = reader.getVersion();
+ xmlStandalone = reader.isStandalone();
+ xmlEncoding = reader.getCharacterEncodingScheme();
+ if (contentHandler != null)
+ contentHandler.startDocument();
+ startDocumentDone = true;
+ break;
+ case XMLStreamConstants.END_DOCUMENT:
+ if (contentHandler != null)
+ contentHandler.endDocument();
+ break;
+ case XMLStreamConstants.DTD:
+ XMLParser.Doctype doctype = parser.doctype;
+ if (lexicalHandler != null)
+ {
+ String rootName = doctype.rootName;
+ String publicId = doctype.publicId;
+ String systemId2 = doctype.systemId;
+ lexicalHandler.startDTD(rootName, publicId, systemId2);
+ }
+ for (Iterator i = doctype.entryIterator(); i.hasNext(); )
+ {
+ String entry = (String) i.next();
+ char c = entry.charAt(0);
+ String name = entry.substring(1);
+ if ('E' == c)
+ {
+ // Element decl
+ if (declHandler != null)
+ {
+ XMLParser.ContentModel model =
+ doctype.getElementModel(name);
+ declHandler.elementDecl(name, model.text);
+ }
+ }
+ else if ('A' == c)
+ {
+ // Attlist decl
+ if (declHandler != null)
+ {
+ for (Iterator j = doctype.attlistIterator(name);
+ j.hasNext(); )
+ {
+ Map.Entry att = (Map.Entry) j.next();
+ String aname = (String) att.getKey();
+ XMLParser.AttributeDecl decl =
+ (XMLParser.AttributeDecl) att.getValue();
+ String type = decl.type;
+ String value = decl.value;
+ String mode = null;
+ switch (decl.valueType)
+ {
+ case XMLParser.ATTRIBUTE_DEFAULT_FIXED:
+ mode = "#FIXED";
+ break;
+ case XMLParser.ATTRIBUTE_DEFAULT_REQUIRED:
+ mode = "#REQUIRED";
+ break;
+ case XMLParser.ATTRIBUTE_DEFAULT_IMPLIED:
+ mode = "#IMPLIED";
+ break;
+ }
+ declHandler.attributeDecl(name, aname,
+ type, mode, value);
+ }
+ }
+ }
+ else if ('e' == c)
+ {
+ // Entity decl
+ Object entity = doctype.getEntity(name);
+ if (entity instanceof String)
+ {
+ if (declHandler != null)
+ declHandler.internalEntityDecl(name,
+ (String) entity);
+ }
+ else
+ {
+ XMLParser.ExternalIds ids =
+ (XMLParser.ExternalIds) entity;
+ if (ids.notationName != null)
+ {
+ if (dtdHandler != null)
+ {
+ String pub = ids.publicId;
+ String url = ids.systemId;
+ String not = ids.notationName;
+ dtdHandler.unparsedEntityDecl(name,
+ pub,
+ url,
+ not);
+ }
+ }
+ else
+ {
+ if (declHandler != null)
+ {
+ String pub = ids.publicId;
+ String url = ids.systemId;
+ declHandler.externalEntityDecl(name,
+ pub,
+ url);
+ }
+ }
+ }
+ }
+ else if ('n' == c)
+ {
+ // Notation decl
+ if (dtdHandler != null)
+ {
+ XMLParser.ExternalIds ids =
+ doctype.getNotation(name);
+ String pub = ids.publicId;
+ String url = ids.systemId;
+ dtdHandler.notationDecl(name, pub, url);
+ }
+ }
+ else if ('c' == c)
+ {
+ // Comment
+ if (lexicalHandler != null)
+ {
+ String comment = doctype.getComment(name);
+ char[] b = comment.toCharArray();
+ lexicalHandler.comment(b, 0, b.length);
+ }
+ }
+ else if ('p' == c)
+ {
+ // Processing instruction
+ if (contentHandler != null)
+ {
+ String[] pi = doctype.getPI(name);
+ String target = pi[0];
+ String data = pi[1];
+ if (data == null)
+ data = "";
+ contentHandler.processingInstruction(target, data);
+ }
+ }
+ }
+ if (lexicalHandler != null)
+ lexicalHandler.endDTD();
+ }
+ }
+ }
+ catch (XMLStreamException e)
+ {
+ if (!startDocumentDone && contentHandler != null)
+ contentHandler.startDocument();
+ SAXParseException e2 = new SAXParseException(e.getMessage(), this);
+ e2.initCause(e);
+ if (errorHandler != null)
+ errorHandler.fatalError(e2);
+ if (contentHandler != null)
+ contentHandler.endDocument();
+ throw e2;
+ }
+ finally
+ {
+ if (opened)
+ in.close();
+ reset();
+ }
+ }
+
+ /**
+ * Indicates whether the specified characters are ignorable whitespace.
+ */
+ private boolean isIgnorableWhitespace(XMLParser reader, char[] b,
+ boolean testCharacters)
+ throws XMLStreamException
+ {
+ XMLParser.Doctype doctype = reader.doctype;
+ if (doctype == null)
+ return false;
+ String currentElement = reader.getCurrentElement();
+ // check for xml:space
+ int ac = reader.getAttributeCount();
+ for (int i = 0; i < ac; i++)
+ {
+ QName aname = reader.getAttributeQName(i);
+ if ("space".equals(aname.getLocalPart()) &&
+ XMLConstants.XML_NS_URI.equals(aname.getNamespaceURI()))
+ {
+ if ("preserve".equals(reader.getAttributeValue(i)))
+ return false;
+ }
+ }
+ XMLParser.ContentModel model = doctype.getElementModel(currentElement);
+ if (model == null || model.type != XMLParser.ContentModel.ELEMENT)
+ return false;
+ if (model.external && xmlStandalone)
+ return false;
+ boolean white = true;
+ if (testCharacters)
+ {
+ for (int i = 0; i < b.length; i++)
+ {
+ if (b[i] != ' ' && b[i] != '\t' && b[i] != '\n' && b[i] != '\r')
+ {
+ white = false;
+ break;
+ }
+ }
+ }
+ return white;
+ }
+
+ public void parse(String systemId)
+ throws IOException, SAXException
+ {
+ parse(new InputSource(systemId));
+ }
+
+ // -- Attributes2 --
+
+ public int getIndex(String qName)
+ {
+ int len = reader.getAttributeCount();
+ for (int i = 0; i < len; i++)
+ {
+ QName q = reader.getAttributeQName(i);
+ String localName = q.getLocalPart();
+ String prefix = q.getPrefix();
+ String qn = ("".equals(prefix)) ? localName : prefix + ":" + localName;
+ if (qName.equals(qn))
+ return i;
+ }
+ return -1;
+ }
+
+ public int getIndex(String uri, String localName)
+ {
+ int len = reader.getAttributeCount();
+ for (int i = 0; i < len; i++)
+ {
+ QName q = reader.getAttributeQName(i);
+ String ln = q.getLocalPart();
+ String u = q.getNamespaceURI();
+ if (u == null && uri != null)
+ continue;
+ if (u != null && !u.equals(uri))
+ continue;
+ if (ln.equals(localName))
+ return i;
+ }
+ return -1;
+ }
+
+ public int getLength()
+ {
+ return reader.getAttributeCount();
+ }
+
+ public String getLocalName(int index)
+ {
+ return reader.getAttributeName(index);
+ }
+
+ public String getQName(int index)
+ {
+ QName q = reader.getAttributeQName(index);
+ String localName = q.getLocalPart();
+ String prefix = q.getPrefix();
+ return ("".equals(prefix)) ? localName : prefix + ":" + localName;
+ }
+
+ public String getType(int index)
+ {
+ String ret = reader.getAttributeType(index);
+ // SAX doesn't permit ENUMERATION?
+ return ("ENUMERATION".equals(ret)) ? "NMTOKEN" : ret;
+ }
+
+ public String getType(String qName)
+ {
+ int index = getIndex(qName);
+ return (index == -1) ? null : getType(index);
+ }
+
+ public String getType(String uri, String localName)
+ {
+ int index = getIndex(uri, localName);
+ return (index == -1) ? null : getType(index);
+ }
+
+ public String getURI(int index)
+ {
+ String ret = reader.getAttributeNamespace(index);
+ return (ret == null) ? "" : ret;
+ }
+
+ public String getValue(int index)
+ {
+ return reader.getAttributeValue(index);
+ }
+
+ public String getValue(String qName)
+ {
+ int index = getIndex(qName);
+ return (index == -1) ? null : getValue(index);
+ }
+
+ public String getValue(String uri, String localName)
+ {
+ int index = getIndex(uri, localName);
+ return (index == -1) ? null : getValue(index);
+ }
+
+ public boolean isDeclared(int index)
+ {
+ return parser.isAttributeDeclared(index);
+ }
+
+ public boolean isDeclared(String qName)
+ {
+ int index = getIndex(qName);
+ return (index == -1) ? false : isDeclared(index);
+ }
+
+ public boolean isDeclared(String uri, String localName)
+ {
+ int index = getIndex(uri, localName);
+ return (index == -1) ? false : isDeclared(index);
+ }
+
+ public boolean isSpecified(int index)
+ {
+ return reader.isAttributeSpecified(index);
+ }
+
+ public boolean isSpecified(String qName)
+ {
+ int index = getIndex(qName);
+ return (index == -1) ? false : isSpecified(index);
+ }
+
+ public boolean isSpecified(String uri, String localName)
+ {
+ int index = getIndex(uri, localName);
+ return (index == -1) ? false : isSpecified(index);
+ }
+
+ // -- Locator2 --
+
+ public int getColumnNumber()
+ {
+ Location l = reader.getLocation();
+ return l.getColumnNumber();
+ }
+
+ public int getLineNumber()
+ {
+ Location l = reader.getLocation();
+ return l.getLineNumber();
+ }
+
+ public String getPublicId()
+ {
+ return null;
+ }
+
+ public String getSystemId()
+ {
+ Location l = reader.getLocation();
+ return l.getLocationURI();
+ }
+
+ public String getEncoding()
+ {
+ return encoding;
+ }
+
+ public String getXMLVersion()
+ {
+ return xmlVersion;
+ }
+
+ // -- XMLResolver --
+
+ public InputStream resolve(String uri)
+ throws XMLStreamException
+ {
+ return resolve(null, uri);
+ }
+
+ public InputStream resolve(String publicId, String systemId)
+ throws XMLStreamException
+ {
+ if (entityResolver != null)
+ {
+ try
+ {
+ InputSource input =
+ entityResolver.resolveEntity(publicId, systemId);
+ if (input != null)
+ return input.getByteStream();
+ }
+ catch (SAXException e)
+ {
+ XMLStreamException e2 = new XMLStreamException(e.getMessage());
+ e2.initCause(e);
+ throw e2;
+ }
+ catch (IOException e)
+ {
+ XMLStreamException e2 = new XMLStreamException(e.getMessage());
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+ return null;
+ }
+
+ public XMLEventReader resolveAsXMLEventReader(String uri)
+ throws XMLStreamException
+ {
+ // unused
+ return null;
+ }
+
+ public XMLStreamReader resolveAsXMLStreamReader(String uri)
+ throws XMLStreamException
+ {
+ // unused
+ return null;
+ }
+
+ // -- XMLReporter --
+
+ public void report(String message, String errorType,
+ Object relatedInformation, Location location)
+ throws XMLStreamException
+ {
+ if (errorHandler != null)
+ {
+ try
+ {
+ errorHandler.warning(new SAXParseException(message, this));
+ }
+ catch (SAXException e)
+ {
+ XMLStreamException e2 = new XMLStreamException(e.getMessage());
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+ }
+
+ public static void main(String[] args)
+ throws Exception
+ {
+ SAXParser parser = new SAXParser();
+ InputSource input = new InputSource(args[0]);
+ parser.parse(input, new org.xml.sax.helpers.DefaultHandler());
+
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/stream/SAXParserFactory.java b/libjava/classpath/gnu/xml/stream/SAXParserFactory.java
new file mode 100644
index 00000000000..a2ccea1e694
--- /dev/null
+++ b/libjava/classpath/gnu/xml/stream/SAXParserFactory.java
@@ -0,0 +1,104 @@
+/* SAXParserFactory.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath 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, or (at your option)
+any later version.
+
+GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.stream;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+
+/**
+ * SAX parser factory providing a SAX compatibility layer on top of StAX.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class SAXParserFactory
+ extends javax.xml.parsers.SAXParserFactory
+{
+
+ static final Set FEATURE_NAMES = new HashSet();
+ static
+ {
+ FEATURE_NAMES.add("http://xml.org/sax/features/namespaces");
+ FEATURE_NAMES.add("http://xml.org/sax/features/string-interning");
+ FEATURE_NAMES.add("http://xml.org/sax/features/validation");
+ }
+
+ Map features = new HashMap();
+
+ public javax.xml.parsers.SAXParser newSAXParser()
+ throws ParserConfigurationException, SAXException
+ {
+ boolean validating = isValidating();
+ boolean namespaceAware = isNamespaceAware();
+ boolean xIncludeAware = isXIncludeAware();
+ SAXParser ret = new SAXParser(validating, namespaceAware, xIncludeAware);
+ for (Iterator i = features.entrySet().iterator(); i.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ String name = (String) entry.getKey();
+ Boolean value = (Boolean) entry.getValue();
+ ret.setFeature(name, value.booleanValue());
+ }
+ return ret;
+ }
+
+ public void setFeature(String name, boolean value)
+ throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException
+ {
+ if (!FEATURE_NAMES.contains(name))
+ throw new SAXNotSupportedException(name);
+ features.put(name, value ? Boolean.TRUE : Boolean.FALSE);
+ }
+
+ public boolean getFeature(String name)
+ throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException
+ {
+ if (!FEATURE_NAMES.contains(name))
+ throw new SAXNotSupportedException(name);
+ Boolean value = (Boolean) features.get(name);
+ return (value == null) ? false : value.booleanValue();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/stream/UnicodeReader.java b/libjava/classpath/gnu/xml/stream/UnicodeReader.java
new file mode 100644
index 00000000000..c38516c30f8
--- /dev/null
+++ b/libjava/classpath/gnu/xml/stream/UnicodeReader.java
@@ -0,0 +1,201 @@
+/* UnicodeReader.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath 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, or (at your option)
+any later version.
+
+GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.stream;
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * A reader that converts UTF-16 characters to Unicode code points.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class UnicodeReader
+{
+
+ final Reader in;
+
+ UnicodeReader(Reader in)
+ {
+ this.in = in;
+ }
+
+ public void mark(int limit)
+ throws IOException
+ {
+ in.mark(limit * 2);
+ }
+
+ public void reset()
+ throws IOException
+ {
+ in.reset();
+ }
+
+ public int read()
+ throws IOException
+ {
+ int ret = in.read();
+ if (ret == -1)
+ return ret;
+ if (ret >= 0xd800 && ret < 0xdc00)
+ {
+ // Unicode surrogate?
+ int low = in.read();
+ if (low >= 0xdc00 && low < 0xe000)
+ ret = Character.toCodePoint((char) ret, (char) low);
+ else
+ throw new IOException("unpaired surrogate: U+" +
+ Integer.toHexString(ret));
+ }
+ else if (ret >= 0xdc00 && ret < 0xe000)
+ throw new IOException("unpaired surrogate: U+" +
+ Integer.toHexString(ret));
+ return ret;
+ }
+
+ public int read(int[] buf, int off, int len)
+ throws IOException
+ {
+ if (len == 0)
+ return 0;
+ char[] b2 = new char[len];
+ int ret = in.read(b2, 0, len);
+ if (ret <= 0)
+ return ret;
+ int l = ret - 1;
+ int i = 0, j = off;
+ for (; i < l; i++)
+ {
+ char c = b2[i];
+ if (c >= 0xd800 && c < 0xdc00)
+ {
+ // Unicode surrogate?
+ char d = b2[i + 1];
+ if (d >= 0xdc00 && d < 0xe000)
+ {
+ buf[j++] = Character.toCodePoint(c, d);
+ i++;
+ continue;
+ }
+ else
+ throw new IOException("unpaired surrogate: U+" +
+ Integer.toHexString(c));
+ }
+ else if (c >= 0xdc00 && c < 0xe000)
+ throw new IOException("unpaired surrogate: U+" +
+ Integer.toHexString(c));
+ buf[j++] = (int) c;
+ }
+ if (i == l)
+ {
+ // last char
+ char c = b2[l];
+ if (c >= 0xd800 && c < 0xdc00)
+ {
+ int low = in.read();
+ if (low >= 0xdc00 && low < 0xe000)
+ {
+ buf[j++] = Character.toCodePoint(c, (char) low);
+ return j;
+ }
+ else
+ throw new IOException("unpaired surrogate: U+" +
+ Integer.toHexString(c));
+ }
+ else if (c >= 0xdc00 && c < 0xe000)
+ throw new IOException("unpaired surrogate: U+" +
+ Integer.toHexString(c));
+ buf[j++] = (int) c;
+ }
+ return j;
+ }
+
+ public void close()
+ throws IOException
+ {
+ in.close();
+ }
+
+ public static int[] toCodePointArray(String text)
+ throws IOException
+ {
+ char[] b2 = text.toCharArray();
+ int[] buf = new int[b2.length];
+ if (b2.length > 0)
+ {
+ int l = b2.length - 1;
+ int i = 0, j = 0;
+ for (; i < l; i++)
+ {
+ char c = b2[i];
+ if (c >= 0xd800 && c < 0xdc00)
+ {
+ // Unicode surrogate?
+ char d = b2[i + 1];
+ if (d >= 0xdc00 && d < 0xe000)
+ {
+ buf[j++] = Character.toCodePoint(c, d);
+ i++;
+ continue;
+ }
+ else
+ throw new IOException("unpaired surrogate: U+" +
+ Integer.toHexString(c));
+ }
+ else if (c >= 0xdc00 && c < 0xe000)
+ throw new IOException("unpaired surrogate: U+" +
+ Integer.toHexString(c));
+ buf[j++] = (int) c;
+ }
+ if (i == l)
+ {
+ // last char
+ buf[j++] = (int) b2[l];
+ if (j < buf.length)
+ {
+ int[] buf2 = new int[j];
+ System.arraycopy(buf, 0, buf2, 0, j);
+ buf = buf2;
+ }
+ }
+ }
+ return buf;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/stream/XIncludeFilter.java b/libjava/classpath/gnu/xml/stream/XIncludeFilter.java
new file mode 100644
index 00000000000..e151ac69d3c
--- /dev/null
+++ b/libjava/classpath/gnu/xml/stream/XIncludeFilter.java
@@ -0,0 +1,932 @@
+/* XIncludeFilter.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath 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, or (at your option)
+any later version.
+
+GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.stream;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.HashSet;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.util.ReaderDelegate;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.TypeInfo;
+import org.w3c.dom.traversal.DocumentTraversal;
+import org.w3c.dom.traversal.NodeFilter;
+import org.w3c.dom.traversal.TreeWalker;
+import org.w3c.dom.xpath.XPathEvaluator;
+import org.w3c.dom.xpath.XPathNSResolver;
+import org.w3c.dom.xpath.XPathResult;
+import org.xml.sax.SAXException;
+
+/**
+ * StAX filter for performing XInclude processing.
+ *
+ * @see http://www.w3.org/TR/xinclude/
+ * @see http://www.w3.org/TR/xptr-framework/
+ * @see http://www.w3.org/TR/xptr-element/
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class XIncludeFilter
+ extends ReaderDelegate
+{
+
+ static final String XINCLUDE_NS_URI = "http://www.w3.org/2001/XInclude";
+ static final int SHOW_FLAGS =
+ NodeFilter.SHOW_CDATA_SECTION |
+ NodeFilter.SHOW_COMMENT |
+ NodeFilter.SHOW_ELEMENT |
+ NodeFilter.SHOW_ENTITY_REFERENCE |
+ NodeFilter.SHOW_PROCESSING_INSTRUCTION |
+ NodeFilter.SHOW_TEXT;
+
+ final String systemId;
+ final boolean namespaceAware;
+ final boolean validating;
+ final boolean expandERefs;
+ String href;
+ int event;
+ boolean included;
+ XPathResult result;
+ int snapshotIndex;
+ Node current;
+ TreeWalker walker;
+ HashSet seen = new HashSet();
+ boolean backtracking;
+ boolean lookahead;
+
+ Reader includedText;
+ char[] buf;
+ int len = -1;
+ boolean inInclude, inFallback, seenFallback;
+
+ DocumentBuilder builder;
+
+ XIncludeFilter(XMLStreamReader reader, String systemId,
+ boolean namespaceAware, boolean validating,
+ boolean expandERefs)
+ {
+ super(reader);
+ this.systemId = XMLParser.absolutize(null, systemId);
+ this.namespaceAware = namespaceAware;
+ this.validating = validating;
+ this.expandERefs = expandERefs;
+ }
+
+ public int getAttributeCount()
+ {
+ if (current != null)
+ {
+ NamedNodeMap attrs = current.getAttributes();
+ return (attrs == null) ? 0 : attrs.getLength();
+ }
+ return super.getAttributeCount();
+ }
+
+ public String getAttributeName(int index)
+ {
+ if (current != null)
+ {
+ NamedNodeMap attrs = current.getAttributes();
+ if (attrs == null)
+ return null;
+ Node attr = attrs.item(index);
+ return attr.getLocalName();
+ }
+ return super.getAttributeName(index);
+ }
+
+ public String getAttributeNamespace(int index)
+ {
+ if (current != null)
+ {
+ NamedNodeMap attrs = current.getAttributes();
+ if (attrs == null)
+ return null;
+ Node attr = attrs.item(index);
+ return attr.getNamespaceURI();
+ }
+ return super.getAttributeNamespace(index);
+ }
+
+ public String getAttributePrefix(int index)
+ {
+ if (current != null)
+ {
+ NamedNodeMap attrs = current.getAttributes();
+ if (attrs == null)
+ return null;
+ Node attr = attrs.item(index);
+ return attr.getPrefix();
+ }
+ return super.getAttributePrefix(index);
+ }
+
+ public QName getAttributeQName(int index)
+ {
+ if (current != null)
+ {
+ NamedNodeMap attrs = current.getAttributes();
+ if (attrs == null)
+ return null;
+ Node attr = attrs.item(index);
+ String localName = attr.getLocalName();
+ String uri = attr.getNamespaceURI();
+ String prefix = attr.getPrefix();
+ return new QName(uri, localName, prefix);
+ }
+ return super.getAttributeQName(index);
+ }
+
+ public String getAttributeType(int index)
+ {
+ if (current != null)
+ {
+ NamedNodeMap attrs = current.getAttributes();
+ if (attrs == null)
+ return null;
+ Attr attr = (Attr) attrs.item(index);
+ TypeInfo ti = attr.getSchemaTypeInfo();
+ return (ti == null) ? "CDATA" : ti.getTypeName();
+ }
+ return super.getAttributeType(index);
+ }
+
+ public boolean isAttributeSpecified(int index)
+ {
+ if (current != null)
+ {
+ NamedNodeMap attrs = current.getAttributes();
+ if (attrs == null)
+ return false;
+ Attr attr = (Attr) attrs.item(index);
+ return attr.getSpecified();
+ }
+ return super.isAttributeSpecified(index);
+ }
+
+ public String getAttributeValue(int index)
+ {
+ if (current != null)
+ {
+ NamedNodeMap attrs = current.getAttributes();
+ if (attrs == null)
+ return null;
+ Node attr = attrs.item(index);
+ return attr.getNodeValue();
+ }
+ return super.getAttributeValue(index);
+ }
+
+ public String getAttributeValue(String uri, String localName)
+ {
+ if (current != null)
+ {
+ NamedNodeMap attrs = current.getAttributes();
+ if (attrs == null)
+ return null;
+ Node attr = attrs.getNamedItemNS(uri, localName);
+ return (attr == null) ? null : attr.getNodeValue();
+ }
+ return super.getAttributeValue(uri, localName);
+ }
+
+ public String getElementText()
+ throws XMLStreamException
+ {
+ if (current != null)
+ return current.getTextContent();
+ return super.getElementText();
+ }
+
+ public int getEventType()
+ {
+ return event;
+ }
+
+ public String getLocalName()
+ {
+ if (current != null)
+ return current.getLocalName();
+ return super.getLocalName();
+ }
+
+ public QName getName()
+ {
+ if (current != null)
+ {
+ String localName = current.getLocalName();
+ String uri = current.getNamespaceURI();
+ String prefix = current.getPrefix();
+ return new QName(uri, localName, prefix);
+ }
+ return super.getName();
+ }
+
+ public String getNamespaceURI()
+ {
+ if (current != null)
+ return current.getNamespaceURI();
+ return super.getNamespaceURI();
+ }
+
+ // TODO namespaces
+
+ public String getPIData()
+ {
+ if (current != null)
+ return ((ProcessingInstruction) current).getData();
+ return super.getPIData();
+ }
+
+ public String getPITarget()
+ {
+ if (current != null)
+ return ((ProcessingInstruction) current).getTarget();
+ return super.getPITarget();
+ }
+
+ public String getPrefix()
+ {
+ if (current != null)
+ return current.getPrefix();
+ return super.getPrefix();
+ }
+
+ public String getText()
+ {
+ if (current != null)
+ return current.getNodeValue();
+ if (walker != null)
+ {
+ Node n = walker.getCurrentNode();
+ if (n != null)
+ return n.getTextContent();
+ }
+ if (buf != null)
+ return new String(buf, 0, len);
+ return super.getText();
+ }
+
+ public char[] getTextCharacters()
+ {
+ if (current != null)
+ {
+ buf = current.getNodeValue().toCharArray();
+ len = buf.length;
+ }
+ if (buf != null)
+ return buf;
+ return super.getTextCharacters();
+ }
+
+ public int getTextCharacters(int sourceStart, char[] target,
+ int targetStart, int length)
+ throws XMLStreamException
+ {
+ if (current != null)
+ {
+ buf = current.getNodeValue().toCharArray();
+ len = buf.length;
+ }
+ if (buf != null)
+ {
+ int max = Math.min(len - sourceStart, length);
+ if (max > 0)
+ System.arraycopy(buf, sourceStart, target, targetStart, max);
+ return max;
+ }
+ return super.getTextCharacters(sourceStart, target, targetStart, length);
+ }
+
+ public int getTextLength()
+ {
+ if (current != null)
+ {
+ buf = current.getNodeValue().toCharArray();
+ len = buf.length;
+ }
+ if (buf != null)
+ return len;
+ return super.getTextLength();
+ }
+
+ public int getTextStart()
+ {
+ if (current != null)
+ {
+ buf = current.getNodeValue().toCharArray();
+ len = buf.length;
+ }
+ if (buf != null)
+ return 0;
+ return super.getTextStart();
+ }
+
+ public boolean hasNext()
+ throws XMLStreamException
+ {
+ if (!lookahead)
+ {
+ try
+ {
+ next();
+ }
+ catch (NoSuchElementException e)
+ {
+ event = -1;
+ }
+ lookahead = true;
+ }
+ return (event != -1);
+ }
+
+ public int next()
+ throws XMLStreamException
+ {
+ if (lookahead)
+ {
+ lookahead = false;
+ return event;
+ }
+ buf = null;
+ len = 0;
+ if (walker != null)
+ {
+ Node c = walker.getCurrentNode();
+ Node n = null;
+ if (c.getNodeType() == Node.ELEMENT_NODE)
+ {
+ boolean isStartElement = !seen.contains(c);
+ if (isStartElement)
+ {
+ seen.add(c);
+ current = c;
+ event = XMLStreamConstants.START_ELEMENT;
+ return event;
+ }
+ else if (backtracking)
+ {
+ n = walker.nextSibling();
+ if (n != null)
+ backtracking = false;
+ }
+ else
+ {
+ n = walker.firstChild();
+ if (n == null)
+ n = walker.nextSibling();
+ }
+ }
+ else
+ {
+ n = walker.firstChild();
+ if (n == null)
+ n = walker.nextSibling();
+ }
+ if (n == null)
+ {
+ current = walker.parentNode();
+ if (current != null && current.getNodeType() == Node.ELEMENT_NODE)
+ {
+ // end-element
+ backtracking = true;
+ event = XMLStreamConstants.END_ELEMENT;
+ return event;
+ }
+ else
+ {
+ walker = null;
+ current = null;
+ }
+ }
+ else
+ {
+ current = n;
+ switch (n.getNodeType())
+ {
+ case Node.ELEMENT_NODE:
+ return next();
+ case Node.TEXT_NODE:
+ String text = n.getNodeValue();
+ buf = text.toCharArray();
+ len = buf.length;
+ event = isSpace(buf, len) ?
+ XMLStreamConstants.SPACE :
+ XMLStreamConstants.CHARACTERS;
+ return event;
+ case Node.CDATA_SECTION_NODE:
+ event = XMLStreamConstants.CDATA;
+ return event;
+ case Node.COMMENT_NODE:
+ event = XMLStreamConstants.COMMENT;
+ return event;
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ event = XMLStreamConstants.PROCESSING_INSTRUCTION;
+ return event;
+ case Node.ENTITY_REFERENCE_NODE:
+ event = XMLStreamConstants.ENTITY_REFERENCE;
+ return event;
+ default:
+ throw new IllegalStateException();
+ }
+ }
+ }
+ if (result != null)
+ {
+ switch (result.getResultType())
+ {
+ case XPathResult.BOOLEAN_TYPE:
+ boolean bval = result.getBooleanValue();
+ String btext = bval ? "true" : "false";
+ buf = btext.toCharArray();
+ len = buf.length;
+ result = null;
+ event = XMLStreamConstants.CHARACTERS;
+ return event;
+ case XPathResult.NUMBER_TYPE:
+ double nval = result.getNumberValue();
+ String ntext = new Double(nval).toString();
+ buf = ntext.toCharArray();
+ len = buf.length;
+ result = null;
+ event = XMLStreamConstants.CHARACTERS;
+ return event;
+ case XPathResult.STRING_TYPE:
+ String stext = result.getStringValue();
+ buf = stext.toCharArray();
+ len = buf.length;
+ result = null;
+ event = isSpace(buf, len) ?
+ XMLStreamConstants.SPACE :
+ XMLStreamConstants.CHARACTERS;
+ return event;
+ case XPathResult.ANY_UNORDERED_NODE_TYPE:
+ case XPathResult.FIRST_ORDERED_NODE_TYPE:
+ Node n1 = result.getSingleNodeValue();
+ Document d1 = getDocument(n1);
+ walker = getDocumentTraversal(d1)
+ .createTreeWalker(n1, SHOW_FLAGS, null, expandERefs);
+ result = null;
+ return next();
+ case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
+ case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
+ Node n2 = result.iterateNext();
+ if (n2 == null)
+ {
+ result = null;
+ return next();
+ }
+ Document d2 = getDocument(n2);
+ walker = getDocumentTraversal(d2)
+ .createTreeWalker(n2, SHOW_FLAGS, null, expandERefs);
+ return next();
+ case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
+ case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
+ Node n3 = result.snapshotItem(snapshotIndex++);
+ if (n3 == null)
+ {
+ result = null;
+ return next();
+ }
+ Document d3 = getDocument(n3);
+ walker = getDocumentTraversal(d3)
+ .createTreeWalker(n3, SHOW_FLAGS, null, expandERefs);
+ return next();
+ default:
+ throw new IllegalStateException();
+ }
+ }
+ if (includedText != null)
+ {
+ // fill buffer
+ if (buf == null)
+ buf = new char[2048];
+ try
+ {
+ len = includedText.read(buf, 0, buf.length);
+ if (len == -1)
+ {
+ includedText = null;
+ buf = null;
+ return next();
+ }
+ // chars or space?
+ return (event = isSpace(buf, len) ?
+ XMLStreamConstants.SPACE :
+ XMLStreamConstants.CHARACTERS);
+ }
+ catch (IOException e)
+ {
+ XMLStreamException e2 = new XMLStreamException(e.getMessage());
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+ event = super.next();
+ switch (event)
+ {
+ case XMLStreamConstants.START_ELEMENT:
+ String uri = getNamespaceURI();
+ if (XINCLUDE_NS_URI.equals(uri))
+ {
+ String localName = getLocalName();
+ if ("include".equals(localName))
+ {
+ href = getAttributeValue(null, "href");
+ String parse = getAttributeValue(null, "parse");
+ String xpointer = getAttributeValue(null, "xpointer");
+ String encoding = getAttributeValue(null, "encoding");
+ String accept = getAttributeValue(null, "accept");
+ String acceptLanguage = getAttributeValue(null,
+ "accept-language");
+ if (includeResource(href, parse, xpointer, encoding,
+ accept, acceptLanguage))
+ {
+ // Skip to xi:include end-element event
+ int depth = 0;
+ while (depth >= 0)
+ {
+ event = super.next();
+ switch (event)
+ {
+ case XMLStreamConstants.START_ELEMENT:
+ depth++;
+ break;
+ case XMLStreamConstants.END_ELEMENT:
+ depth--;
+ }
+ }
+ }
+ else
+ inInclude = true;
+ }
+ else if (inInclude && "fallback".equals(localName))
+ {
+ if (!seenFallback)
+ inFallback = seenFallback = true;
+ else
+ throw new XMLStreamException("duplicate xi:fallback element");
+ }
+ else if (inInclude)
+ {
+ throw new XMLStreamException("illegal xi element '" +
+ localName + "'");
+ }
+ return next();
+ }
+ break;
+ case XMLStreamConstants.END_ELEMENT:
+ String uri2 = getNamespaceURI();
+ if (XINCLUDE_NS_URI.equals(uri2))
+ {
+ String localName = getLocalName();
+ if ("include".equals(localName))
+ {
+ if (!seenFallback && included)
+ {
+ String msg = "Unable to read " + href +
+ " and no xi:fallback element present";
+ throw new XMLStreamException(msg);
+ }
+ included = false;
+ href = null;
+ inInclude = inFallback = seenFallback = false;
+ }
+ else if ("fallback".equals(localName))
+ inFallback = false;
+ return next();
+ }
+ break;
+ }
+ if (inInclude && !inFallback)
+ return next();
+ return event;
+ }
+
+ boolean isSpace(char[] text, int len)
+ {
+ boolean space = true;
+ for (int i = 0; i < len; i++)
+ {
+ char c = text[i];
+ if (c != ' ' && c != '\t' && c != '\n' && c != '\r')
+ {
+ space = false;
+ break;
+ }
+ }
+ return space;
+ }
+
+ String getBaseURI()
+ {
+ String base = (String) getParent().getProperty("gnu.xml.stream.baseURI");
+ return (base == null) ? systemId : base;
+ }
+
+ boolean includeResource(String href, String parse, String xpointer,
+ String encoding, String accept,
+ String acceptLanguage)
+ {
+ included = false;
+ try
+ {
+ if (xpointer != null)
+ throw new XMLStreamException("xpointer attribute not yet supported");
+ String base = getBaseURI();
+ if (href == null || "".equals(href))
+ href = base;
+ else
+ href = XMLParser.absolutize(base, href);
+ if (parse == null || "xml".equals(parse))
+ {
+ seen.clear();
+ result = null;
+ snapshotIndex = 0;
+ walker = null;
+ current = null;
+ backtracking = false;
+
+ URLConnection connection = getURLConnection(href, accept,
+ acceptLanguage);
+ InputStream in = connection.getInputStream();
+ Document doc = getDocumentBuilder().parse(in, href);
+ DocumentTraversal dt = getDocumentTraversal(doc);
+ if (xpointer == null)
+ {
+ result = null;
+ Node item = doc.getDocumentElement();
+ walker = dt.createTreeWalker(item, SHOW_FLAGS, null,
+ expandERefs);
+ }
+ else
+ {
+ result = null;
+ snapshotIndex = 0;
+ walker = null;
+ // shorthand or scheme-based?
+ int lpi = xpointer.indexOf('(');
+ int rpi = xpointer.indexOf(')', lpi);
+ if (lpi != -1 && rpi != -1)
+ {
+ String scheme = xpointer.substring(0, lpi);
+ if ("element".equals(scheme))
+ {
+ // element() scheme
+ String elementSchemeData =
+ xpointer.substring(lpi + 1, rpi);
+ Node item = doc;
+ int si = elementSchemeData.indexOf('/');
+ if (si == -1)
+ {
+ if (elementSchemeData.length() > 0)
+ item = doc.getElementById(elementSchemeData);
+ }
+ else
+ {
+ if (si > 0)
+ {
+ String context =
+ elementSchemeData.substring(0, si);
+ item = doc.getElementById(context);
+ elementSchemeData =
+ elementSchemeData.substring(si + 1);
+ }
+ StringTokenizer st =
+ new StringTokenizer(elementSchemeData, "/");
+ while (st.hasMoreTokens() && item != null)
+ {
+ int n = Integer.parseInt(st.nextToken());
+ Node ctx = item.getFirstChild();
+ int count = 1;
+ while (ctx != null && count++ < n)
+ ctx = ctx.getNextSibling();
+ item = ctx;
+ }
+ }
+ walker = dt.createTreeWalker(item, SHOW_FLAGS, null,
+ expandERefs);
+ included = true;
+ }
+ else if ("xpointer".equals(scheme))
+ {
+ xpointer = xpointer.substring(lpi + 1, rpi);
+ XPathEvaluator eval = getXPathEvaluator(doc);
+ XPathNSResolver resolver = eval.createNSResolver(doc);
+ result =
+ (XPathResult) eval.evaluate(xpointer, doc,
+ resolver,
+ XPathResult.ANY_TYPE,
+ null);
+ // TODO xpointer() scheme functions
+ included = true;
+ }
+ else
+ {
+ String msg = "Unknown XPointer scheme: " + scheme;
+ throw new XMLStreamException(msg);
+ }
+ }
+ else
+ {
+ Node item = doc.getElementById(xpointer);
+ walker = dt.createTreeWalker(item, SHOW_FLAGS, null,
+ expandERefs);
+ included = true;
+ }
+ }
+ }
+ else if ("text".equals(parse))
+ {
+ URLConnection connection = getURLConnection(href, accept,
+ acceptLanguage);
+ InputStream in = connection.getInputStream();
+ if (encoding == null)
+ {
+ encoding = connection.getContentEncoding();
+ if (encoding == null)
+ {
+ String contentType = connection.getContentType();
+ if (contentType != null)
+ encoding = getParameter(contentType, "charset");
+ }
+ }
+ if (encoding == null)
+ includedText = new InputStreamReader(in, "UTF-8");
+ else
+ includedText = new InputStreamReader(in, encoding);
+ included = true;
+ }
+ else
+ throw new XMLStreamException("value of 'parse' attribute must be "+
+ "'xml' or 'text'");
+ return true;
+ }
+ catch (IOException e)
+ {
+ return false;
+ }
+ catch (XMLStreamException e)
+ {
+ return false;
+ }
+ catch (SAXException e)
+ {
+ return false;
+ }
+ }
+
+ URLConnection getURLConnection(String href, String accept,
+ String acceptLanguage)
+ throws IOException
+ {
+ URL url = new URL(href);
+ URLConnection connection = url.openConnection();
+ if (connection instanceof HttpURLConnection)
+ {
+ HttpURLConnection http = (HttpURLConnection) connection;
+ http.setInstanceFollowRedirects(true);
+ if (accept != null)
+ http.setRequestProperty("Accept", accept);
+ if (acceptLanguage != null)
+ http.setRequestProperty("Accept-Language", acceptLanguage);
+ }
+ return connection;
+ }
+
+ Document getDocument(Node node)
+ {
+ if (node.getNodeType() == Node.DOCUMENT_NODE)
+ return (Document) node;
+ return node.getOwnerDocument();
+ }
+
+ DocumentBuilder getDocumentBuilder()
+ throws XMLStreamException
+ {
+ if (builder == null)
+ {
+ try
+ {
+ DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
+ f.setXIncludeAware(true);
+ f.setNamespaceAware(namespaceAware);
+ f.setValidating(validating);
+ builder = f.newDocumentBuilder();
+ }
+ catch (ParserConfigurationException e)
+ {
+ XMLStreamException e2 = new XMLStreamException(e.getMessage());
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+ builder.reset();
+ return builder;
+ }
+
+ DocumentTraversal getDocumentTraversal(Document doc)
+ throws XMLStreamException
+ {
+ DOMImplementation dom = doc.getImplementation();
+ if (!dom.hasFeature("Traversal", "2.0"))
+ throw new XMLStreamException("Traversal not supported");
+ return (DocumentTraversal) doc;
+ }
+
+ XPathEvaluator getXPathEvaluator(Document doc)
+ throws XMLStreamException
+ {
+ DOMImplementation dom = doc.getImplementation();
+ if (!dom.hasFeature("XPath", "3.0"))
+ throw new XMLStreamException("XPath not supported");
+ return (XPathEvaluator) doc;
+ }
+
+ static String getParameter(String contentType, String name)
+ {
+ StringTokenizer st = new StringTokenizer(contentType, " ;");
+ if (st.hasMoreTokens())
+ st.nextToken();
+ while (st.hasMoreTokens())
+ {
+ String token = st.nextToken();
+ int ei = token.indexOf('=');
+ if (ei != -1)
+ {
+ String key = token.substring(0, ei);
+ if (key.equals(name))
+ {
+ String value = token.substring(ei + 1);
+ int len = value.length();
+ if (len > 1 &&
+ value.charAt(0) == '"' &&
+ value.charAt(len - 1) == '"')
+ value = value.substring(1, len - 1);
+ else if (len > 1 &&
+ value.charAt(0) == '\'' &&
+ value.charAt(len - 1) == '\'')
+ value = value.substring(1, len - 1);
+ return value;
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/stream/XMLInputFactoryImpl.java b/libjava/classpath/gnu/xml/stream/XMLInputFactoryImpl.java
index c99f564b623..164774d8236 100644
--- a/libjava/classpath/gnu/xml/stream/XMLInputFactoryImpl.java
+++ b/libjava/classpath/gnu/xml/stream/XMLInputFactoryImpl.java
@@ -77,6 +77,9 @@ public class XMLInputFactoryImpl
protected boolean replacingEntityReferences = true;
protected boolean externalEntities = true;
protected boolean supportDTD = true;
+ protected boolean xIncludeAware = false;
+ protected boolean baseAware = true;
+ protected boolean stringInterning = true;
public XMLInputFactoryImpl()
{
@@ -86,11 +89,28 @@ public class XMLInputFactoryImpl
public XMLStreamReader createXMLStreamReader(Reader reader)
throws XMLStreamException
{
+ /*
return new XMLStreamReaderImpl(reader, null, null,
resolver, reporter,
validating, namespaceAware,
coalescing, replacingEntityReferences,
externalEntities, supportDTD);
+ */
+ XMLParser ret = new XMLParser(reader, null,
+ validating,
+ namespaceAware,
+ coalescing,
+ replacingEntityReferences,
+ externalEntities,
+ supportDTD,
+ baseAware,
+ stringInterning,
+ reporter,
+ resolver);
+ if (xIncludeAware)
+ return new XIncludeFilter(ret, null, namespaceAware, validating,
+ replacingEntityReferences);
+ return ret;
}
public XMLStreamReader createXMLStreamReader(Source source)
@@ -98,21 +118,51 @@ public class XMLInputFactoryImpl
{
String systemId = source.getSystemId();
InputStream in = getInputStream(source);
- return new XMLStreamReaderImpl(in, null, systemId,
+ /*return new XMLStreamReaderImpl(in, null, systemId,
resolver, reporter,
validating, namespaceAware,
coalescing, replacingEntityReferences,
- externalEntities, supportDTD);
+ externalEntities, supportDTD);*/
+ XMLParser ret = new XMLParser(in, systemId,
+ validating,
+ namespaceAware,
+ coalescing,
+ replacingEntityReferences,
+ externalEntities,
+ supportDTD,
+ baseAware,
+ stringInterning,
+ reporter,
+ resolver);
+ if (xIncludeAware)
+ return new XIncludeFilter(ret, systemId, namespaceAware, validating,
+ replacingEntityReferences);
+ return ret;
}
public XMLStreamReader createXMLStreamReader(InputStream in)
throws XMLStreamException
{
- return new XMLStreamReaderImpl(in, null, null,
+ /*return new XMLStreamReaderImpl(in, null, null,
resolver, reporter,
validating, namespaceAware,
coalescing, replacingEntityReferences,
- externalEntities, supportDTD);
+ externalEntities, supportDTD);*/
+ XMLParser ret = new XMLParser(in, null,
+ validating,
+ namespaceAware,
+ coalescing,
+ replacingEntityReferences,
+ externalEntities,
+ supportDTD,
+ baseAware,
+ stringInterning,
+ reporter,
+ resolver);
+ if (xIncludeAware)
+ return new XIncludeFilter(ret, null, namespaceAware, validating,
+ replacingEntityReferences);
+ return ret;
}
public XMLStreamReader createXMLStreamReader(InputStream in, String encoding)
@@ -210,6 +260,12 @@ public class XMLInputFactoryImpl
resolver = (XMLResolver) value;
else if (name.equals(ALLOCATOR))
allocator = (XMLEventAllocator) value;
+ else if (name.equals("gnu.xml.stream.stringInterning"))
+ stringInterning = ((Boolean) value).booleanValue();
+ else if (name.equals("gnu.xml.stream.baseAware"))
+ baseAware = ((Boolean) value).booleanValue();
+ else if (name.equals("gnu.xml.stream.xIncludeAware"))
+ xIncludeAware = ((Boolean) value).booleanValue();
else
throw new IllegalArgumentException(name);
}
@@ -235,6 +291,12 @@ public class XMLInputFactoryImpl
return resolver;
if (name.equals(ALLOCATOR))
return allocator;
+ if (name.equals("gnu.xml.stream.stringInterning"))
+ return stringInterning ? Boolean.TRUE : Boolean.FALSE;
+ if (name.equals("gnu.xml.stream.baseAware"))
+ return baseAware ? Boolean.TRUE : Boolean.FALSE;
+ if (name.equals("gnu.xml.stream.xIncludeAware"))
+ return xIncludeAware ? Boolean.TRUE : Boolean.FALSE;
throw new IllegalArgumentException(name);
}
@@ -248,7 +310,10 @@ public class XMLInputFactoryImpl
name.equals(SUPPORT_DTD) ||
name.equals(REPORTER) ||
name.equals(RESOLVER) ||
- name.equals(ALLOCATOR);
+ name.equals(ALLOCATOR) ||
+ name.equals("gnu.xml.stream.stringInterning") ||
+ name.equals("gnu.xml.stream.baseAware") ||
+ name.equals("gnu.xml.stream.xIncludeAware");
}
public void setEventAllocator(XMLEventAllocator allocator)
diff --git a/libjava/classpath/gnu/xml/stream/XMLParser.java b/libjava/classpath/gnu/xml/stream/XMLParser.java
new file mode 100644
index 00000000000..6f10b9303dc
--- /dev/null
+++ b/libjava/classpath/gnu/xml/stream/XMLParser.java
@@ -0,0 +1,5266 @@
+/* XMLParser.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath 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, or (at your option)
+any later version.
+
+GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version.
+
+Partly derived from code which carried the following notice:
+
+ Copyright (c) 1997, 1998 by Microstar Software Ltd.
+
+ AElfred is free for both commercial and non-commercial use and
+ redistribution, provided that Microstar's copyright and disclaimer are
+ retained intact. You are free to modify AElfred for your own use and
+ to redistribute AElfred with your modifications, provided that the
+ modifications are clearly documented.
+
+ 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. Please use it AT
+ YOUR OWN RISK.
+*/
+
+package gnu.xml.stream;
+
+import java.io.BufferedInputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLReporter;
+import javax.xml.stream.XMLResolver;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import gnu.java.net.CRLFInputStream;
+
+/**
+ * An XML parser.
+ * This parser supports the following additional StAX properties:
+ * <table>
+ * <tr><td>gnu.xml.stream.stringInterning</td>
+ * <td>Boolean</td>
+ * <td>Indicates whether markup strings will be interned</td></tr>
+ * <tr><td>gnu.xml.stream.xmlBase</td>
+ * <td>Boolean</td>
+ * <td>Indicates whether XML Base processing will be performed</td></tr>
+ * <tr><td>gnu.xml.stream.baseURI</td>
+ * <td>String</td>
+ * <td>Returns the base URI of the current event</td></tr>
+ * </table>
+ *
+ * @see http://www.w3.org/TR/REC-xml/
+ * @see http://www.w3.org/TR/xml11/
+ * @see http://www.w3.org/TR/REC-xml-names
+ * @see http://www.w3.org/TR/xml-names11
+ * @see http://www.w3.org/TR/xmlbase/
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class XMLParser
+ implements XMLStreamReader, NamespaceContext
+{
+
+ // -- parser state machine states --
+ private static final int INIT = 0; // start state
+ private static final int PROLOG = 1; // in prolog
+ private static final int CONTENT = 2; // in content
+ private static final int EMPTY_ELEMENT = 3; // empty element state
+ private static final int MISC = 4; // in Misc (after root element)
+
+ // -- parameters for parsing literals --
+ private final static int LIT_ENTITY_REF = 2;
+ private final static int LIT_NORMALIZE = 4;
+ private final static int LIT_ATTRIBUTE = 8;
+ private final static int LIT_DISABLE_PE = 16;
+ private final static int LIT_DISABLE_CREF = 32;
+ private final static int LIT_DISABLE_EREF = 64;
+ private final static int LIT_PUBID = 256;
+
+ // -- types of attribute values --
+ final static int ATTRIBUTE_DEFAULT_UNDECLARED = 30;
+ final static int ATTRIBUTE_DEFAULT_SPECIFIED = 31;
+ final static int ATTRIBUTE_DEFAULT_IMPLIED = 32;
+ final static int ATTRIBUTE_DEFAULT_REQUIRED = 33;
+ final static int ATTRIBUTE_DEFAULT_FIXED = 34;
+
+ /**
+ * The current input.
+ */
+ private Input input;
+
+ /**
+ * Stack of inputs representing XML general entities.
+ * The input representing the XML input stream or reader is always the
+ * first element in this stack.
+ */
+ private LinkedList inputStack = new LinkedList();
+
+ /**
+ * Stack of start-entity events to be reported.
+ */
+ private LinkedList startEntityStack = new LinkedList();
+
+ /**
+ * Stack of end-entity events to be reported.
+ */
+ private LinkedList endEntityStack = new LinkedList();
+
+ /**
+ * Current parser state within the main state machine.
+ */
+ private int state = INIT;
+
+ /**
+ * The (type of the) current event.
+ */
+ private int event;
+
+ /**
+ * Whether we are looking ahead. Used by hasNext.
+ */
+ private boolean lookahead;
+
+ /**
+ * The element name stack. The first element in this stack will be the
+ * root element.
+ */
+ private LinkedList stack = new LinkedList();
+
+ /**
+ * Stack of namespace contexts. These are maps specifying prefix-to-URI
+ * mappings. The first element in this stack is the most recent namespace
+ * context (i.e. the other way around from the element name stack).
+ */
+ private LinkedList namespaces = new LinkedList();
+
+ /**
+ * The base-URI stack. This holds the base URI context for each element.
+ * The first element in this stack is the most recent context (i.e. the
+ * other way around from the element name stack).
+ */
+ private LinkedList bases = new LinkedList();
+
+ /**
+ * The list of attributes for the current element, in the order defined in
+ * the XML stream.
+ */
+ private ArrayList attrs = new ArrayList();
+
+ /**
+ * Buffer for text and character data.
+ */
+ private StringBuffer buf = new StringBuffer();
+
+ /**
+ * Buffer for NMTOKEN strings (markup).
+ */
+ private StringBuffer nmtokenBuf = new StringBuffer();
+
+ /**
+ * Buffer for string literals. (e.g. attribute values)
+ */
+ private StringBuffer literalBuf = new StringBuffer();
+
+ /**
+ * Temporary Unicode character buffer used during character data reads.
+ */
+ private int[] tmpBuf = new int[1024];
+
+ /**
+ * The element content model for the current element.
+ */
+ private ContentModel currentContentModel;
+
+ /**
+ * The validation stack. This holds lists of the elements seen for each
+ * element, in order to determine whether the names and order of these
+ * elements match the content model for the element. The last entry in
+ * this stack represents the current element.
+ */
+ private LinkedList validationStack;
+
+ /**
+ * These sets contain the IDs and the IDREFs seen in the document, to
+ * ensure that IDs are unique and that each IDREF refers to an ID in the
+ * document.
+ */
+ private HashSet ids, idrefs;
+
+ /**
+ * The target and data associated with the current processing instruction
+ * event.
+ */
+ private String piTarget, piData;
+
+ /**
+ * The XML version declared in the XML declaration.
+ */
+ private String xmlVersion;
+
+ /**
+ * The encoding declared in the XML declaration.
+ */
+ private String xmlEncoding;
+
+ /**
+ * The standalone value declared in the XML declaration.
+ */
+ private Boolean xmlStandalone;
+
+ /**
+ * The document type definition.
+ */
+ Doctype doctype;
+
+ /**
+ * State variables for determining parameter-entity expansion.
+ */
+ private boolean expandPE, peIsError;
+
+ /**
+ * Whether this is a validating parser.
+ */
+ private final boolean validating;
+
+ /**
+ * Whether strings representing markup will be interned.
+ */
+ private final boolean stringInterning;
+
+ /**
+ * If true, CDATA sections will be merged with adjacent text nodes into a
+ * single event.
+ */
+ private final boolean coalescing;
+
+ /**
+ * Whether to replace general entity references with their replacement
+ * text automatically during parsing.
+ * Otherwise entity-reference events will be issued.
+ */
+ private final boolean replaceERefs;
+
+ /**
+ * Whether to support external entities.
+ */
+ private final boolean externalEntities;
+
+ /**
+ * Whether to support DTDs.
+ */
+ private final boolean supportDTD;
+
+ /**
+ * Whether to support XML namespaces. If true, namespace information will
+ * be available. Otherwise namespaces will simply be reported as ordinary
+ * attributes.
+ */
+ private final boolean namespaceAware;
+
+ /**
+ * Whether to support XML Base. If true, URIs specified in xml:base
+ * attributes will be honoured when resolving external entities.
+ */
+ private final boolean baseAware;
+
+ /**
+ * The reporter to receive parsing warnings.
+ */
+ final XMLReporter reporter;
+
+ /**
+ * Callback interface for resolving external entities.
+ */
+ final XMLResolver resolver;
+
+ // -- Constants for testing the next kind of markup event --
+ private static final String TEST_START_ELEMENT = "<";
+ private static final String TEST_END_ELEMENT = "</";
+ private static final String TEST_COMMENT = "<!--";
+ private static final String TEST_PI = "<?";
+ private static final String TEST_CDATA = "<![CDATA[";
+ private static final String TEST_XML_DECL = "<?xml";
+ private static final String TEST_DOCTYPE_DECL = "<!DOCTYPE";
+ private static final String TEST_ELEMENT_DECL = "<!ELEMENT";
+ private static final String TEST_ATTLIST_DECL = "<!ATTLIST";
+ private static final String TEST_ENTITY_DECL = "<!ENTITY";
+ private static final String TEST_NOTATION_DECL = "<!NOTATION";
+ private static final String TEST_KET = ">";
+ private static final String TEST_END_COMMENT = "--";
+ private static final String TEST_END_PI = "?>";
+ private static final String TEST_END_CDATA = "]]>";
+
+ /**
+ * The general entities predefined by the XML specification.
+ */
+ private static final LinkedHashMap PREDEFINED_ENTITIES = new LinkedHashMap();
+ static
+ {
+ PREDEFINED_ENTITIES.put("amp", "&");
+ PREDEFINED_ENTITIES.put("lt", "<");
+ PREDEFINED_ENTITIES.put("gt", ">");
+ PREDEFINED_ENTITIES.put("apos", "'");
+ PREDEFINED_ENTITIES.put("quot", "\"");
+ }
+
+ /**
+ * Creates a new XML parser for the given input stream.
+ * This constructor should be used where possible, as it allows the
+ * encoding of the XML data to be correctly determined from the stream.
+ * @param in the input stream
+ * @param systemId the URL from which the input stream was retrieved
+ * (necessary if there are external entities to be resolved)
+ * @param validating if the parser is to be a validating parser
+ * @param namespaceAware if the parser should support XML Namespaces
+ * @param coalescing if CDATA sections should be merged into adjacent text
+ * nodes
+ * @param replaceERefs if entity references should be automatically
+ * replaced by their replacement text (otherwise they will be reported as
+ * entity-reference events)
+ * @param externalEntities if external entities should be loaded
+ * @param supportDTD if support for the XML DTD should be enabled
+ * @param baseAware if the parser should support XML Base to resolve
+ * external entities
+ * @param stringInterning whether strings will be interned during parsing
+ * @param reporter the reporter to receive warnings during processing
+ * @param resolver the callback interface used to resolve external
+ * entities
+ */
+ public XMLParser(InputStream in, String systemId,
+ boolean validating,
+ boolean namespaceAware,
+ boolean coalescing,
+ boolean replaceERefs,
+ boolean externalEntities,
+ boolean supportDTD,
+ boolean baseAware,
+ boolean stringInterning,
+ XMLReporter reporter,
+ XMLResolver resolver)
+ {
+ this.validating = validating;
+ this.namespaceAware = namespaceAware;
+ this.coalescing = coalescing;
+ this.replaceERefs = replaceERefs;
+ this.externalEntities = externalEntities;
+ this.supportDTD = supportDTD;
+ this.baseAware = baseAware;
+ this.stringInterning = stringInterning;
+ this.reporter = reporter;
+ this.resolver = resolver;
+ if (validating)
+ {
+ validationStack = new LinkedList();
+ ids = new HashSet();
+ idrefs = new HashSet();
+ }
+ pushInput(new Input(in, null, null, systemId, null, null, false, true));
+ }
+
+ /**
+ * Creates a new XML parser for the given character stream.
+ * This constructor is only available for compatibility with the JAXP
+ * APIs, which permit XML to be parsed from a character stream. Because
+ * the encoding specified by the character stream may conflict with that
+ * specified in the XML declaration, this method should be avoided where
+ * possible.
+ * @param in the input stream
+ * @param systemId the URL from which the input stream was retrieved
+ * (necessary if there are external entities to be resolved)
+ * @param validating if the parser is to be a validating parser
+ * @param namespaceAware if the parser should support XML Namespaces
+ * @param coalescing if CDATA sections should be merged into adjacent text
+ * nodes
+ * @param replaceERefs if entity references should be automatically
+ * replaced by their replacement text (otherwise they will be reported as
+ * entity-reference events)
+ * @param externalEntities if external entities should be loaded
+ * @param supportDTD if support for the XML DTD should be enabled
+ * @param baseAware if the parser should support XML Base to resolve
+ * external entities
+ * @param stringInterning whether strings will be interned during parsing
+ * @param reporter the reporter to receive warnings during processing
+ * @param resolver the callback interface used to resolve external
+ * entities
+ */
+ public XMLParser(Reader reader, String systemId,
+ boolean validating,
+ boolean namespaceAware,
+ boolean coalescing,
+ boolean replaceERefs,
+ boolean externalEntities,
+ boolean supportDTD,
+ boolean baseAware,
+ boolean stringInterning,
+ XMLReporter reporter,
+ XMLResolver resolver)
+ {
+ this.validating = validating;
+ this.namespaceAware = namespaceAware;
+ this.coalescing = coalescing;
+ this.replaceERefs = replaceERefs;
+ this.externalEntities = externalEntities;
+ this.supportDTD = supportDTD;
+ this.baseAware = baseAware;
+ this.stringInterning = stringInterning;
+ this.reporter = reporter;
+ this.resolver = resolver;
+ if (validating)
+ {
+ validationStack = new LinkedList();
+ ids = new HashSet();
+ idrefs = new HashSet();
+ }
+ pushInput(new Input(null, reader, null, systemId, null, null, false, true));
+ }
+
+ // -- NamespaceContext --
+
+ public String getNamespaceURI(String prefix)
+ {
+ if (XMLConstants.XML_NS_PREFIX.equals(prefix))
+ return XMLConstants.XML_NS_URI;
+ if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix))
+ return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
+ for (Iterator i = namespaces.iterator(); i.hasNext(); )
+ {
+ LinkedHashMap ctx = (LinkedHashMap) i.next();
+ String namespaceURI = (String) ctx.get(prefix);
+ if (namespaceURI != null)
+ return namespaceURI;
+ }
+ return null;
+ }
+
+ public String getPrefix(String namespaceURI)
+ {
+ if (XMLConstants.XML_NS_URI.equals(namespaceURI))
+ return XMLConstants.XML_NS_PREFIX;
+ if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI))
+ return XMLConstants.XMLNS_ATTRIBUTE;
+ for (Iterator i = namespaces.iterator(); i.hasNext(); )
+ {
+ LinkedHashMap ctx = (LinkedHashMap) i.next();
+ if (ctx.containsValue(namespaceURI))
+ {
+ for (Iterator j = ctx.entrySet().iterator(); j.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ String uri = (String) entry.getValue();
+ if (uri.equals(namespaceURI))
+ return (String) entry.getKey();
+ }
+ }
+ }
+ return null;
+ }
+
+ public Iterator getPrefixes(String namespaceURI)
+ {
+ if (XMLConstants.XML_NS_URI.equals(namespaceURI))
+ return Collections.singleton(XMLConstants.XML_NS_PREFIX).iterator();
+ if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI))
+ return Collections.singleton(XMLConstants.XMLNS_ATTRIBUTE).iterator();
+ LinkedList acc = new LinkedList();
+ for (Iterator i = namespaces.iterator(); i.hasNext(); )
+ {
+ LinkedHashMap ctx = (LinkedHashMap) i.next();
+ if (ctx.containsValue(namespaceURI))
+ {
+ for (Iterator j = ctx.entrySet().iterator(); j.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ String uri = (String) entry.getValue();
+ if (uri.equals(namespaceURI))
+ acc.add(entry.getKey());
+ }
+ }
+ }
+ return acc.iterator();
+ }
+
+ // -- XMLStreamReader --
+
+ public void close()
+ throws XMLStreamException
+ {
+ stack = null;
+ namespaces = null;
+ bases = null;
+ buf = null;
+ attrs = null;
+ doctype = null;
+
+ inputStack = null;
+ validationStack = null;
+ ids = null;
+ idrefs = null;
+ }
+
+ public NamespaceContext getNamespaceContext()
+ {
+ return this;
+ }
+
+ public int getAttributeCount()
+ {
+ return attrs.size();
+ }
+
+ public String getAttributeName(int index)
+ {
+ Attribute a = (Attribute) attrs.get(index);
+ return a.localName;
+ }
+
+ public String getAttributeNamespace(int index)
+ {
+ String prefix = getAttributePrefix(index);
+ return getNamespaceURI(prefix);
+ }
+
+ public String getAttributePrefix(int index)
+ {
+ Attribute a = (Attribute) attrs.get(index);
+ return a.prefix;
+ }
+
+ public QName getAttributeQName(int index)
+ {
+ Attribute a = (Attribute) attrs.get(index);
+ String namespaceURI = getNamespaceURI(a.prefix);
+ return new QName(namespaceURI, a.localName, a.prefix);
+ }
+
+ public String getAttributeType(int index)
+ {
+ Attribute a = (Attribute) attrs.get(index);
+ return a.type;
+ }
+
+ private String getAttributeType(String elementName, String attName)
+ {
+ if (doctype != null)
+ {
+ AttributeDecl att = doctype.getAttributeDecl(elementName, attName);
+ if (att != null)
+ return att.type;
+ }
+ return "CDATA";
+ }
+
+ public String getAttributeValue(int index)
+ {
+ Attribute a = (Attribute) attrs.get(index);
+ return a.value;
+ }
+
+ public String getAttributeValue(String namespaceURI, String localName)
+ {
+ for (Iterator i = attrs.iterator(); i.hasNext(); )
+ {
+ Attribute a = (Attribute) i.next();
+ if (a.localName.equals(localName))
+ {
+ String uri = getNamespaceURI(a.prefix);
+ if ((uri == null && namespaceURI == null) ||
+ (uri != null && uri.equals(namespaceURI)))
+ return a.value;
+ }
+ }
+ return null;
+ }
+
+ boolean isAttributeDeclared(int index)
+ {
+ if (doctype == null)
+ return false;
+ Attribute a = (Attribute) attrs.get(index);
+ String qn = ("".equals(a.prefix)) ? a.localName :
+ a.prefix + ":" + a.localName;
+ String elementName = buf.toString();
+ return doctype.isAttributeDeclared(elementName, qn);
+ }
+
+ public String getCharacterEncodingScheme()
+ {
+ return xmlEncoding;
+ }
+
+ public String getElementText()
+ throws XMLStreamException
+ {
+ if (event != XMLStreamConstants.START_ELEMENT)
+ throw new XMLStreamException("current event must be START_ELEMENT");
+ StringBuffer elementText = new StringBuffer();
+ int depth = stack.size();
+ while (event != XMLStreamConstants.END_ELEMENT || stack.size() > depth)
+ {
+ switch (next())
+ {
+ case XMLStreamConstants.CHARACTERS:
+ case XMLStreamConstants.SPACE:
+ elementText.append(buf.toString());
+ }
+ }
+ return elementText.toString();
+ }
+
+ public String getEncoding()
+ {
+ return (input.inputEncoding == null) ? "UTF-8" : input.inputEncoding;
+ }
+
+ public int getEventType()
+ {
+ return event;
+ }
+
+ public String getLocalName()
+ {
+ switch (event)
+ {
+ case XMLStreamConstants.START_ELEMENT:
+ case XMLStreamConstants.END_ELEMENT:
+ String qName = buf.toString();
+ int ci = qName.indexOf(':');
+ return (ci == -1) ? qName : qName.substring(ci + 1);
+ default:
+ return null;
+ }
+ }
+
+ public Location getLocation()
+ {
+ return input;
+ }
+
+ public QName getName()
+ {
+ switch (event)
+ {
+ case XMLStreamConstants.START_ELEMENT:
+ case XMLStreamConstants.END_ELEMENT:
+ String qName = buf.toString();
+ int ci = qName.indexOf(':');
+ String localName = (ci == -1) ? qName : qName.substring(ci + 1);
+ String prefix = (ci == -1) ?
+ (namespaceAware ? XMLConstants.DEFAULT_NS_PREFIX : null) :
+ qName.substring(0, ci);
+ String namespaceURI = getNamespaceURI(prefix);
+ return new QName(namespaceURI, localName, prefix);
+ default:
+ return null;
+ }
+ }
+
+ public int getNamespaceCount()
+ {
+ if (!namespaceAware)
+ return 0;
+ switch (event)
+ {
+ case XMLStreamConstants.START_ELEMENT:
+ case XMLStreamConstants.END_ELEMENT:
+ LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst();
+ return ctx.size();
+ default:
+ return 0;
+ }
+ }
+
+ public String getNamespacePrefix(int index)
+ {
+ LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst();
+ int count = 0;
+ for (Iterator i = ctx.keySet().iterator(); i.hasNext(); )
+ {
+ String prefix = (String) i.next();
+ if (count++ == index)
+ return prefix;
+ }
+ return null;
+ }
+
+ public String getNamespaceURI()
+ {
+ switch (event)
+ {
+ case XMLStreamConstants.START_ELEMENT:
+ case XMLStreamConstants.END_ELEMENT:
+ String qName = buf.toString();
+ int ci = qName.indexOf(':');
+ if (ci == -1)
+ return null;
+ String prefix = qName.substring(0, ci);
+ return getNamespaceURI(prefix);
+ default:
+ return null;
+ }
+ }
+
+ public String getNamespaceURI(int index)
+ {
+ LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst();
+ int count = 0;
+ for (Iterator i = ctx.values().iterator(); i.hasNext(); )
+ {
+ String uri = (String) i.next();
+ if (count++ == index)
+ return uri;
+ }
+ return null;
+ }
+
+ public String getPIData()
+ {
+ return piData;
+ }
+
+ public String getPITarget()
+ {
+ return piTarget;
+ }
+
+ public String getPrefix()
+ {
+ switch (event)
+ {
+ case XMLStreamConstants.START_ELEMENT:
+ case XMLStreamConstants.END_ELEMENT:
+ String qName = buf.toString();
+ int ci = qName.indexOf(':');
+ return (ci == -1) ?
+ (namespaceAware ? XMLConstants.DEFAULT_NS_PREFIX : null) :
+ qName.substring(0, ci);
+ default:
+ return null;
+ }
+ }
+
+ public Object getProperty(String name)
+ throws IllegalArgumentException
+ {
+ if (name == null)
+ throw new IllegalArgumentException("name is null");
+ if (XMLInputFactory.ALLOCATOR.equals(name))
+ return null;
+ if (XMLInputFactory.IS_COALESCING.equals(name))
+ return coalescing ? Boolean.TRUE : Boolean.FALSE;
+ if (XMLInputFactory.IS_NAMESPACE_AWARE.equals(name))
+ return namespaceAware ? Boolean.TRUE : Boolean.FALSE;
+ if (XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES.equals(name))
+ return replaceERefs ? Boolean.TRUE : Boolean.FALSE;
+ if (XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES.equals(name))
+ return externalEntities ? Boolean.TRUE : Boolean.FALSE;
+ if (XMLInputFactory.IS_VALIDATING.equals(name))
+ return Boolean.FALSE;
+ if (XMLInputFactory.REPORTER.equals(name))
+ return reporter;
+ if (XMLInputFactory.RESOLVER.equals(name))
+ return resolver;
+ if (XMLInputFactory.SUPPORT_DTD.equals(name))
+ return supportDTD ? Boolean.TRUE : Boolean.FALSE;
+ if ("gnu.xml.stream.stringInterning".equals(name))
+ return stringInterning ? Boolean.TRUE : Boolean.FALSE;
+ if ("gnu.xml.stream.xmlBase".equals(name))
+ return baseAware ? Boolean.TRUE : Boolean.FALSE;
+ if ("gnu.xml.stream.baseURI".equals(name))
+ return getXMLBase();
+ return null;
+ }
+
+ public String getText()
+ {
+ return buf.toString();
+ }
+
+ public char[] getTextCharacters()
+ {
+ return buf.toString().toCharArray();
+ }
+
+ public int getTextCharacters(int sourceStart, char[] target,
+ int targetStart, int length)
+ throws XMLStreamException
+ {
+ length = Math.min(sourceStart + buf.length(), length);
+ int sourceEnd = sourceStart + length;
+ buf.getChars(sourceStart, sourceEnd, target, targetStart);
+ return length;
+ }
+
+ public int getTextLength()
+ {
+ return buf.length();
+ }
+
+ public int getTextStart()
+ {
+ return 0;
+ }
+
+ public String getVersion()
+ {
+ return (xmlVersion == null) ? "1.0" : xmlVersion;
+ }
+
+ public boolean hasName()
+ {
+ switch (event)
+ {
+ case XMLStreamConstants.START_ELEMENT:
+ case XMLStreamConstants.END_ELEMENT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public boolean hasText()
+ {
+ switch (event)
+ {
+ case XMLStreamConstants.CHARACTERS:
+ case XMLStreamConstants.SPACE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public boolean isAttributeSpecified(int index)
+ {
+ Attribute a = (Attribute) attrs.get(index);
+ return a.specified;
+ }
+
+ public boolean isCharacters()
+ {
+ return (event == XMLStreamConstants.CHARACTERS);
+ }
+
+ public boolean isEndElement()
+ {
+ return (event == XMLStreamConstants.END_ELEMENT);
+ }
+
+ public boolean isStandalone()
+ {
+ return Boolean.TRUE.equals(xmlStandalone);
+ }
+
+ public boolean isStartElement()
+ {
+ return (event == XMLStreamConstants.START_ELEMENT);
+ }
+
+ public boolean isWhiteSpace()
+ {
+ return (event == XMLStreamConstants.SPACE);
+ }
+
+ public int nextTag()
+ throws XMLStreamException
+ {
+ do
+ {
+ switch (next())
+ {
+ case XMLStreamConstants.START_ELEMENT:
+ case XMLStreamConstants.END_ELEMENT:
+ case XMLStreamConstants.CHARACTERS:
+ case XMLStreamConstants.SPACE:
+ case XMLStreamConstants.COMMENT:
+ case XMLStreamConstants.PROCESSING_INSTRUCTION:
+ break;
+ default:
+ throw new XMLStreamException("Unexpected event type: " + event);
+ }
+ }
+ while (event != XMLStreamConstants.START_ELEMENT &&
+ event != XMLStreamConstants.END_ELEMENT);
+ return event;
+ }
+
+ public void require(int type, String namespaceURI, String localName)
+ throws XMLStreamException
+ {
+ if (event != type)
+ throw new XMLStreamException("Current event type is " + event);
+ if (event == XMLStreamConstants.START_ELEMENT ||
+ event == XMLStreamConstants.END_ELEMENT)
+ {
+ String ln = getLocalName();
+ if (!ln.equals(localName))
+ throw new XMLStreamException("Current local-name is " + ln);
+ String uri = getNamespaceURI();
+ if ((uri == null && namespaceURI != null) ||
+ (uri != null && !uri.equals(namespaceURI)))
+ throw new XMLStreamException("Current namespace URI is " + uri);
+ }
+ }
+
+ public boolean standaloneSet()
+ {
+ return (xmlStandalone != null);
+ }
+
+ public boolean hasNext()
+ throws XMLStreamException
+ {
+ if (event == XMLStreamConstants.END_DOCUMENT)
+ return false;
+ if (!lookahead)
+ {
+ next();
+ lookahead = true;
+ }
+ return event != -1;
+ }
+
+ public int next()
+ throws XMLStreamException
+ {
+ if (lookahead)
+ {
+ lookahead = false;
+ return event;
+ }
+ if (event == XMLStreamConstants.END_ELEMENT)
+ {
+ // Pop namespace context
+ if (namespaceAware)
+ namespaces.removeFirst();
+ // Pop base context
+ if (baseAware)
+ bases.removeFirst();
+ }
+ if (!startEntityStack.isEmpty())
+ {
+ String entityName = (String) startEntityStack.removeFirst();
+ buf.setLength(0);
+ buf.append(entityName);
+ event = XMLStreamConstants.START_ENTITY;
+ return event;
+ }
+ else if (!endEntityStack.isEmpty())
+ {
+ String entityName = (String) endEntityStack.removeFirst();
+ buf.setLength(0);
+ buf.append(entityName);
+ event = XMLStreamConstants.END_ENTITY;
+ return event;
+ }
+ try
+ {
+ if (!input.initialized)
+ input.init();
+ switch (state)
+ {
+ case CONTENT:
+ if (tryRead(TEST_END_ELEMENT))
+ {
+ readEndElement();
+ if (stack.isEmpty())
+ state = MISC;
+ event = XMLStreamConstants.END_ELEMENT;
+ }
+ else if (tryRead(TEST_COMMENT))
+ {
+ readComment(false);
+ event = XMLStreamConstants.COMMENT;
+ }
+ else if (tryRead(TEST_PI))
+ {
+ readPI(false);
+ event = XMLStreamConstants.PROCESSING_INSTRUCTION;
+ }
+ else if (tryRead(TEST_CDATA))
+ {
+ readCDSect();
+ event = XMLStreamConstants.CDATA;
+ }
+ else if (tryRead(TEST_START_ELEMENT))
+ {
+ state = readStartElement();
+ event = XMLStreamConstants.START_ELEMENT;
+ }
+ else
+ {
+ // Check for character reference or predefined entity
+ mark(8);
+ int c = readCh();
+ if (c == 0x26) // '&'
+ {
+ c = readCh();
+ if (c == 0x23) // '#'
+ {
+ reset();
+ event = readCharData(null);
+ }
+ else
+ {
+ // entity reference
+ reset();
+ readCh(); // &
+ readReference();
+ String ref = buf.toString();
+ String text = (String) PREDEFINED_ENTITIES.get(ref);
+ if (text != null)
+ {
+ event = readCharData(text);
+ }
+ else if (replaceERefs && !isUnparsedEntity(ref))
+ {
+ // this will report a start-entity event
+ boolean external = false;
+ if (doctype != null)
+ {
+ Object entity = doctype.getEntity(ref);
+ if (entity instanceof ExternalIds)
+ external = true;
+ }
+ expandEntity(ref, false, external);
+ event = next();
+ }
+ else
+ {
+ event = XMLStreamConstants.ENTITY_REFERENCE;
+ }
+ }
+ }
+ else
+ {
+ reset();
+ event = readCharData(null);
+ if (validating && doctype != null)
+ validatePCData(buf.toString());
+ }
+ }
+ break;
+ case EMPTY_ELEMENT:
+ String elementName = (String) stack.removeLast();
+ buf.setLength(0);
+ buf.append(elementName);
+ state = stack.isEmpty() ? MISC : CONTENT;
+ event = XMLStreamConstants.END_ELEMENT;
+ if (validating && doctype != null)
+ endElementValidationHook();
+ break;
+ case INIT: // XMLDecl?
+ if (tryRead(TEST_XML_DECL))
+ readXMLDecl();
+ input.finalizeEncoding();
+ event = XMLStreamConstants.START_DOCUMENT;
+ state = PROLOG;
+ break;
+ case PROLOG: // Misc* (doctypedecl Misc*)?
+ skipWhitespace();
+ if (doctype == null && tryRead(TEST_DOCTYPE_DECL))
+ {
+ readDoctypeDecl();
+ event = XMLStreamConstants.DTD;
+ }
+ else if (tryRead(TEST_COMMENT))
+ {
+ readComment(false);
+ event = XMLStreamConstants.COMMENT;
+ }
+ else if (tryRead(TEST_PI))
+ {
+ readPI(false);
+ event = XMLStreamConstants.PROCESSING_INSTRUCTION;
+ }
+ else if (tryRead(TEST_START_ELEMENT))
+ {
+ state = readStartElement();
+ event = XMLStreamConstants.START_ELEMENT;
+ }
+ else
+ {
+ int c = readCh();
+ error("no root element: U+" + Integer.toHexString(c));
+ }
+ break;
+ case MISC: // Comment | PI | S
+ skipWhitespace();
+ if (tryRead(TEST_COMMENT))
+ {
+ readComment(false);
+ event = XMLStreamConstants.COMMENT;
+ }
+ else if (tryRead(TEST_PI))
+ {
+ readPI(false);
+ event = XMLStreamConstants.PROCESSING_INSTRUCTION;
+ }
+ else
+ {
+ if (event == XMLStreamConstants.END_DOCUMENT)
+ throw new NoSuchElementException();
+ int c = readCh();
+ if (c != -1)
+ error("Only comments and PIs may appear after " +
+ "the root element");
+ event = XMLStreamConstants.END_DOCUMENT;
+ }
+ break;
+ default:
+ event = -1;
+ }
+ return event;
+ }
+ catch (IOException e)
+ {
+ XMLStreamException e2 = new XMLStreamException();
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+ // package private
+
+ /**
+ * Returns the current element name.
+ */
+ String getCurrentElement()
+ {
+ return (String) stack.getLast();
+ }
+
+ // private
+
+ private void mark(int limit)
+ throws IOException
+ {
+ input.mark(limit);
+ }
+
+ private void reset()
+ throws IOException
+ {
+ input.reset();
+ }
+
+ private int read()
+ throws IOException
+ {
+ return input.read();
+ }
+
+ private int read(int[] b, int off, int len)
+ throws IOException
+ {
+ return input.read(b, off, len);
+ }
+
+ /**
+ * Parsed character read.
+ */
+ private int readCh()
+ throws IOException, XMLStreamException
+ {
+ int c = read();
+ if (expandPE && c == 0x25) // '%'
+ {
+ if (peIsError)
+ error("PE reference within decl in internal subset.");
+ expandPEReference();
+ return readCh();
+ }
+ return c;
+ }
+
+ /**
+ * Reads the next character, ensuring it is the character specified.
+ * @param delim the character to match
+ * @exception XMLStreamException if the next character is not the
+ * specified one
+ */
+ private void require(char delim)
+ throws IOException, XMLStreamException
+ {
+ mark(1);
+ int c = readCh();
+ if (delim != c)
+ {
+ reset();
+ error("required character (got U+" + Integer.toHexString(c) + ")",
+ new Character(delim));
+ }
+ }
+
+ /**
+ * Reads the next few characters, ensuring they match the string specified.
+ * @param delim the string to match
+ * @exception XMLStreamException if the next characters do not match the
+ * specified string
+ */
+ private void require(String delim)
+ throws IOException, XMLStreamException
+ {
+ char[] chars = delim.toCharArray();
+ int len = chars.length;
+ mark(len);
+ int off = 0;
+ do
+ {
+ int l2 = read(tmpBuf, off, len - off);
+ if (l2 == -1)
+ {
+ reset();
+ error("EOF before required string", delim);
+ }
+ off += l2;
+ }
+ while (off < len);
+ for (int i = 0; i < chars.length; i++)
+ {
+ if (chars[i] != tmpBuf[i])
+ {
+ reset();
+ error("required string", delim);
+ }
+ }
+ }
+
+ /**
+ * Try to read a single character. On failure, reset the stream.
+ * @param delim the character to test
+ * @return true if the character matched delim, false otherwise.
+ */
+ private boolean tryRead(char delim)
+ throws IOException, XMLStreamException
+ {
+ mark(1);
+ int c = readCh();
+ if (delim != c)
+ {
+ reset();
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Tries to read the specified characters.
+ * If successful, the stream is positioned after the last character,
+ * otherwise it is reset.
+ * @param test the string to test
+ * @return true if the characters matched the test string, false otherwise.
+ */
+ private boolean tryRead(String test)
+ throws IOException
+ {
+ char[] chars = test.toCharArray();
+ int len = chars.length;
+ mark(len);
+ int count = 0;
+ int l2 = read(tmpBuf, 0, len);
+ if (l2 == -1)
+ {
+ reset();
+ return false;
+ }
+ count += l2;
+ while (count < len)
+ {
+ // force read
+ int c = read();
+ if (c == -1)
+ {
+ reset();
+ return false;
+ }
+ tmpBuf[count++] = (char) c;
+ }
+ for (int i = 0; i < len; i++)
+ {
+ if (chars[i] != tmpBuf[i])
+ {
+ reset();
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Reads characters until the specified test string is encountered.
+ * @param delim the string delimiting the end of the characters
+ */
+ private void readUntil(String delim)
+ throws IOException, XMLStreamException
+ {
+ int startLine = input.line;
+ try
+ {
+ while (!tryRead(delim))
+ {
+ int c = readCh();
+ if (c == -1)
+ throw new EOFException();
+ else if (input.xml11)
+ {
+ if (!isXML11Char(c) || isXML11RestrictedChar(c))
+ error("illegal XML 1.1 character",
+ "U+" + Integer.toHexString(c));
+ }
+ else if (!isChar(c))
+ error("illegal XML character",
+ "U+" + Integer.toHexString(c));
+ buf.append(Character.toChars(c));
+ }
+ }
+ catch (EOFException e)
+ {
+ error("end of input while looking for delimiter "+
+ "(started on line " + startLine + ')', delim);
+ }
+ }
+
+ /**
+ * Reads any whitespace characters.
+ * @return true if whitespace characters were read, false otherwise
+ */
+ private boolean tryWhitespace()
+ throws IOException, XMLStreamException
+ {
+ boolean white;
+ boolean ret = false;
+ do
+ {
+ mark(1);
+ int c = readCh();
+ while (c == -1 && inputStack.size() > 1)
+ {
+ popInput();
+ c = readCh();
+ }
+ white = (c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d);
+ if (white)
+ ret = true;
+ }
+ while (white);
+ reset();
+ return ret;
+ }
+
+ /**
+ * Skip over any whitespace characters.
+ */
+ private void skipWhitespace()
+ throws IOException, XMLStreamException
+ {
+ boolean white;
+ do
+ {
+ mark(1);
+ int c = readCh();
+ while (c == -1 && inputStack.size() > 1)
+ {
+ popInput();
+ c = readCh();
+ }
+ white = (c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d);
+ }
+ while (white);
+ reset();
+ }
+
+ /**
+ * Try to read as many whitespace characters as are available.
+ * @exception XMLStreamException if no whitespace characters were seen
+ */
+ private void requireWhitespace()
+ throws IOException, XMLStreamException
+ {
+ if (!tryWhitespace())
+ error("whitespace required");
+ }
+
+ /**
+ * Returns the current base URI for resolving external entities.
+ */
+ String getXMLBase()
+ {
+ if (baseAware)
+ {
+ for (Iterator i = bases.iterator(); i.hasNext(); )
+ {
+ String base = (String) i.next();
+ if (base != null)
+ return base;
+ }
+ }
+ return input.systemId;
+ }
+
+ /**
+ * Push the specified text input source.
+ */
+ private void pushInput(String name, String text, boolean report,
+ boolean normalize)
+ throws IOException, XMLStreamException
+ {
+ // Check for recursion
+ if (name != null && !"".equals(name))
+ {
+ for (Iterator i = inputStack.iterator(); i.hasNext(); )
+ {
+ Input ctx = (Input) i.next();
+ if (name.equals(ctx.name))
+ error("entities may not be self-recursive", name);
+ }
+ }
+ else
+ report = false;
+ pushInput(new Input(null, new StringReader(text), input.publicId,
+ input.systemId, name, input.inputEncoding, report,
+ normalize));
+ }
+
+ /**
+ * Push the specified external input source.
+ */
+ private void pushInput(String name, ExternalIds ids, boolean report,
+ boolean normalize)
+ throws IOException, XMLStreamException
+ {
+ if (!externalEntities)
+ return;
+ InputStream in = null;
+ String url = absolutize(input.systemId, ids.systemId);
+ // Check for recursion
+ for (Iterator i = inputStack.iterator(); i.hasNext(); )
+ {
+ Input ctx = (Input) i.next();
+ if (url.equals(ctx.systemId))
+ error("entities may not be self-recursive", url);
+ if (name != null && !"".equals(name) && name.equals(ctx.name))
+ error("entities may not be self-recursive", name);
+ }
+ if (name == null || "".equals(name))
+ report = false;
+ if (in == null && url != null && resolver != null)
+ {
+ if (resolver instanceof XMLResolver2)
+ in = ((XMLResolver2) resolver).resolve(ids.publicId, url);
+ else
+ in = resolver.resolve(url);
+ }
+ if (in == null)
+ in = resolve(url);
+ if (in == null)
+ error("unable to resolve external entity",
+ (ids.systemId != null) ? ids.systemId : ids.publicId);
+ pushInput(new Input(in, null, ids.publicId, url, name, null, report,
+ normalize));
+ input.init();
+ if (tryRead(TEST_XML_DECL))
+ readTextDecl();
+ input.finalizeEncoding();
+ }
+
+ /**
+ * Push the specified input source (general entity) onto the input stack.
+ */
+ private void pushInput(Input input)
+ {
+ if (input.report)
+ startEntityStack.addFirst(input.name);
+ inputStack.addLast(input);
+ if (this.input != null)
+ input.xml11 = this.input.xml11;
+ this.input = input;
+ }
+
+ /**
+ * "Absolutize" a URL. This resolves a relative URL into an absolute one.
+ * @param base the current base URL
+ * @param href the (absolute or relative) URL to resolve
+ */
+ static String absolutize(String base, String href)
+ {
+ if (href == null)
+ return null;
+ int ci = href.indexOf(':');
+ if (ci > 1 && isLowercaseAscii(href.substring(0, ci)))
+ {
+ // href is absolute already
+ return href;
+ }
+ if (base == null)
+ base = "";
+ else
+ {
+ int i = base.lastIndexOf('/');
+ if (i != -1)
+ base = base.substring(0, i + 1);
+ else
+ base = "";
+ }
+ if ("".equals(base))
+ {
+ // assume file URL relative to current directory
+ base = System.getProperty("user.dir");
+ if (base.charAt(0) == '/')
+ base = base.substring(1);
+ base = "file:///" + base.replace(File.separatorChar, '/');
+ if (!base.endsWith("/"))
+ base += "/";
+ }
+ if (href.startsWith("/"))
+ {
+ if (base.startsWith("file:"))
+ return "file://" + href;
+ int i = base.indexOf("://");
+ if (i != -1)
+ {
+ i = base.indexOf('/', i + 3);
+ if (i != -1)
+ base = base.substring(0, i);
+ }
+ }
+ else
+ {
+ while (href.startsWith(".."))
+ {
+ int i = base.lastIndexOf('/', base.length() - 2);
+ if (i != -1)
+ base = base.substring(0, i + 1);
+ href = href.substring(2);
+ if (href.startsWith("/"))
+ href = href.substring(1);
+ }
+ }
+ return base + href;
+ }
+
+ private static boolean isLowercaseAscii(String text)
+ {
+ int len = text.length();
+ for (int i = 0; i < len; i++)
+ {
+ char c = text.charAt(i);
+ if (c < 97 || c > 122)
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns an input stream for the given URL.
+ */
+ private InputStream resolve(String url)
+ throws IOException
+ {
+ try
+ {
+ return new URL(url).openStream();
+ }
+ catch (MalformedURLException e)
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Pops the current input source (general entity) off the stack.
+ */
+ private void popInput()
+ {
+ Input old = (Input) inputStack.removeLast();
+ if (old.report)
+ endEntityStack.addFirst(old.name);
+ input = (Input) inputStack.getLast();
+ }
+
+ /**
+ * Parse an entity text declaration.
+ */
+ private void readTextDecl()
+ throws IOException, XMLStreamException
+ {
+ final int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF;
+ requireWhitespace();
+ if (tryRead("version"))
+ {
+ readEq();
+ String v = readLiteral(flags, false);
+ if ("1.0".equals(v))
+ input.xml11 = false;
+ else if ("1.1".equals(v))
+ {
+ Input i1 = (Input) inputStack.getFirst();
+ if (!i1.xml11)
+ error("external entity specifies later version number");
+ input.xml11 = true;
+ }
+ else
+ throw new XMLStreamException("illegal XML version: " + v);
+ requireWhitespace();
+ }
+ require("encoding");
+ readEq();
+ String enc = readLiteral(flags, false);
+ skipWhitespace();
+ require("?>");
+ input.setInputEncoding(enc);
+ }
+
+ /**
+ * Parse the XML declaration.
+ */
+ private void readXMLDecl()
+ throws IOException, XMLStreamException
+ {
+ final int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF;
+
+ requireWhitespace();
+ require("version");
+ readEq();
+ xmlVersion = readLiteral(flags, false);
+ if ("1.0".equals(xmlVersion))
+ input.xml11 = false;
+ else if ("1.1".equals(xmlVersion))
+ input.xml11 = true;
+ else
+ throw new XMLStreamException("illegal XML version: " + xmlVersion);
+
+ boolean white = tryWhitespace();
+
+ if (tryRead("encoding"))
+ {
+ if (!white)
+ error("whitespace required before 'encoding='");
+ readEq();
+ xmlEncoding = readLiteral(flags, false);
+ white = tryWhitespace();
+ }
+
+ if (tryRead("standalone"))
+ {
+ if (!white)
+ error("whitespace required before 'standalone='");
+ readEq();
+ String standalone = readLiteral(flags, false);
+ if ("yes".equals(standalone))
+ xmlStandalone = Boolean.TRUE;
+ else if ("no".equals(standalone))
+ xmlStandalone = Boolean.FALSE;
+ else
+ error("standalone flag must be 'yes' or 'no'", standalone);
+ }
+
+ skipWhitespace();
+ require("?>");
+ if (xmlEncoding != null)
+ input.setInputEncoding(xmlEncoding);
+ }
+
+ /**
+ * Parse the DOCTYPE declaration.
+ */
+ private void readDoctypeDecl()
+ throws IOException, XMLStreamException
+ {
+ if (!supportDTD)
+ error("parser was configured not to support DTDs");
+ requireWhitespace();
+ String rootName = readNmtoken(true);
+ skipWhitespace();
+ ExternalIds ids = readExternalIds(false, true);
+ doctype =
+ this.new Doctype(rootName, ids.publicId, ids.systemId);
+
+ // Parse internal subset first
+ skipWhitespace();
+ if (tryRead('['))
+ {
+ while (true)
+ {
+ expandPE = true;
+ skipWhitespace();
+ expandPE = false;
+ if (tryRead(']'))
+ break;
+ else
+ readMarkupdecl(false);
+ }
+ }
+ skipWhitespace();
+ require('>');
+
+ // Parse external subset
+ if (ids.systemId != null && externalEntities)
+ {
+ pushInput("", ">", false, false);
+ pushInput("[dtd]", ids, true, true);
+ // loop until we get back to ">"
+ while (true)
+ {
+ expandPE = true;
+ skipWhitespace();
+ expandPE = false;
+ mark(1);
+ int c = readCh();
+ if (c == 0x3e) // '>'
+ break;
+ else if (c == -1)
+ popInput();
+ else
+ {
+ reset();
+ expandPE = true;
+ readMarkupdecl(true);
+ expandPE = true;
+ }
+ }
+ if (inputStack.size() != 2)
+ error("external subset has unmatched '>'");
+ popInput();
+ }
+ checkDoctype();
+ if (validating)
+ validateDoctype();
+
+ // Make rootName available for reading
+ buf.setLength(0);
+ buf.append(rootName);
+ }
+
+ /**
+ * Checks the well-formedness of the DTD.
+ */
+ private void checkDoctype()
+ throws XMLStreamException
+ {
+ // TODO check entity recursion
+ }
+
+ /**
+ * Parse the markupdecl production.
+ */
+ private void readMarkupdecl(boolean inExternalSubset)
+ throws IOException, XMLStreamException
+ {
+ boolean saved = expandPE;
+ mark(1);
+ require('<');
+ reset();
+ expandPE = false;
+ if (tryRead(TEST_ELEMENT_DECL))
+ {
+ expandPE = saved;
+ readElementDecl();
+ }
+ else if (tryRead(TEST_ATTLIST_DECL))
+ {
+ expandPE = saved;
+ readAttlistDecl();
+ }
+ else if (tryRead(TEST_ENTITY_DECL))
+ {
+ expandPE = saved;
+ readEntityDecl(inExternalSubset);
+ }
+ else if (tryRead(TEST_NOTATION_DECL))
+ {
+ expandPE = saved;
+ readNotationDecl(inExternalSubset);
+ }
+ else if (tryRead(TEST_PI))
+ {
+ readPI(true);
+ expandPE = saved;
+ }
+ else if (tryRead(TEST_COMMENT))
+ {
+ readComment(true);
+ expandPE = saved;
+ }
+ else if (tryRead("<!["))
+ {
+ // conditional section
+ expandPE = saved;
+ if (inputStack.size() < 2)
+ error("conditional sections illegal in internal subset");
+ skipWhitespace();
+ if (tryRead("INCLUDE"))
+ {
+ skipWhitespace();
+ require('[');
+ skipWhitespace();
+ while (!tryRead("]]>"))
+ {
+ readMarkupdecl(inExternalSubset);
+ skipWhitespace();
+ }
+ }
+ else if (tryRead("IGNORE"))
+ {
+ skipWhitespace();
+ require('[');
+ expandPE = false;
+ for (int nesting = 1; nesting > 0; )
+ {
+ int c = readCh();
+ switch (c)
+ {
+ case 0x3c: // '<'
+ if (tryRead("!["))
+ nesting++;
+ break;
+ case 0x5d: // ']'
+ if (tryRead("]>"))
+ nesting--;
+ break;
+ case -1:
+ throw new EOFException();
+ }
+ }
+ expandPE = saved;
+ }
+ else
+ error("conditional section must begin with INCLUDE or IGNORE");
+ }
+ else
+ error("expected markup declaration");
+ }
+
+ /**
+ * Parse the elementdecl production.
+ */
+ private void readElementDecl()
+ throws IOException, XMLStreamException
+ {
+ requireWhitespace();
+ String name = readNmtoken(true);
+ requireWhitespace();
+ readContentspec(name);
+ skipWhitespace();
+ require('>');
+ }
+
+ /**
+ * Parse the contentspec production.
+ */
+ private void readContentspec(String elementName)
+ throws IOException, XMLStreamException
+ {
+ if (tryRead("EMPTY"))
+ doctype.addElementDecl(elementName, "EMPTY", new EmptyContentModel());
+ else if (tryRead("ANY"))
+ doctype.addElementDecl(elementName, "ANY", new AnyContentModel());
+ else
+ {
+ ContentModel model;
+ StringBuffer acc = new StringBuffer();
+ require('(');
+ acc.append('(');
+ skipWhitespace();
+ if (tryRead("#PCDATA"))
+ {
+ // mixed content
+ acc.append("#PCDATA");
+ MixedContentModel mm = new MixedContentModel();
+ model = mm;
+ skipWhitespace();
+ if (tryRead(')'))
+ {
+ acc.append(")");
+ if (tryRead('*'))
+ {
+ mm.min = 0;
+ mm.max = -1;
+ }
+ }
+ else
+ {
+ while (!tryRead(")"))
+ {
+ require('|');
+ acc.append('|');
+ skipWhitespace();
+ String name = readNmtoken(true);
+ acc.append(name);
+ mm.addName(name);
+ skipWhitespace();
+ }
+ require('*');
+ acc.append(")*");
+ mm.min = 0;
+ mm.max = -1;
+ }
+ }
+ else
+ model = readElements(acc);
+ doctype.addElementDecl(elementName, acc.toString(), model);
+ }
+ }
+
+ /**
+ * Parses an element content model.
+ */
+ private ElementContentModel readElements(StringBuffer acc)
+ throws IOException, XMLStreamException
+ {
+ int separator;
+ ElementContentModel model = new ElementContentModel();
+
+ // Parse first content particle
+ skipWhitespace();
+ model.addContentParticle(readContentParticle(acc));
+ // End or separator
+ skipWhitespace();
+ int c = readCh();
+ switch (c)
+ {
+ case 0x29: // ')'
+ acc.append(')');
+ mark(1);
+ c = readCh();
+ switch (c)
+ {
+ case 0x3f: // '?'
+ acc.append('?');
+ model.min = 0;
+ model.max = 1;
+ break;
+ case 0x2a: // '*'
+ acc.append('*');
+ model.min = 0;
+ model.max = -1;
+ break;
+ case 0x2b: // '+'
+ acc.append('+');
+ model.min = 1;
+ model.max = -1;
+ break;
+ default:
+ reset();
+ }
+ return model; // done
+ case 0x7c: // '|'
+ model.or = true;
+ // fall through
+ case 0x2c: // ','
+ separator = c;
+ acc.append(Character.toChars(c));
+ break;
+ default:
+ error("bad separator in content model",
+ "U+" + Integer.toHexString(c));
+ return model;
+ }
+ // Parse subsequent content particles
+ while (true)
+ {
+ skipWhitespace();
+ model.addContentParticle(readContentParticle(acc));
+ skipWhitespace();
+ c = readCh();
+ if (c == 0x29) // ')'
+ {
+ acc.append(')');
+ break;
+ }
+ else if (c != separator)
+ {
+ error("bad separator in content model",
+ "U+" + Integer.toHexString(c));
+ return model;
+ }
+ else
+ acc.append(c);
+ }
+ // Check for occurrence indicator
+ mark(1);
+ c = readCh();
+ switch (c)
+ {
+ case 0x3f: // '?'
+ acc.append('?');
+ model.min = 0;
+ model.max = 1;
+ break;
+ case 0x2a: // '*'
+ acc.append('*');
+ model.min = 0;
+ model.max = -1;
+ break;
+ case 0x2b: // '+'
+ acc.append('+');
+ model.min = 1;
+ model.max = -1;
+ break;
+ default:
+ reset();
+ }
+ return model;
+ }
+
+ /**
+ * Parse a cp production.
+ */
+ private ContentParticle readContentParticle(StringBuffer acc)
+ throws IOException, XMLStreamException
+ {
+ ContentParticle cp = new ContentParticle();
+ if (tryRead('('))
+ {
+ acc.append('(');
+ cp.content = readElements(acc);
+ }
+ else
+ {
+ String name = readNmtoken(true);
+ acc.append(name);
+ cp.content = name;
+ mark(1);
+ int c = readCh();
+ switch (c)
+ {
+ case 0x3f: // '?'
+ acc.append('?');
+ cp.min = 0;
+ cp.max = 1;
+ break;
+ case 0x2a: // '*'
+ acc.append('*');
+ cp.min = 0;
+ cp.max = -1;
+ break;
+ case 0x2b: // '+'
+ acc.append('+');
+ cp.min = 1;
+ cp.max = -1;
+ break;
+ default:
+ reset();
+ }
+ }
+ return cp;
+ }
+
+ /**
+ * Parse an attribute-list definition.
+ */
+ private void readAttlistDecl()
+ throws IOException, XMLStreamException
+ {
+ requireWhitespace();
+ String elementName = readNmtoken(true);
+ boolean white = tryWhitespace();
+ while (!tryRead('>'))
+ {
+ if (!white)
+ error("whitespace required before attribute definition");
+ readAttDef(elementName);
+ white = tryWhitespace();
+ }
+ }
+
+ /**
+ * Parse a single attribute definition.
+ */
+ private void readAttDef(String elementName)
+ throws IOException, XMLStreamException
+ {
+ String name = readNmtoken(true);
+ requireWhitespace();
+ StringBuffer acc = new StringBuffer();
+ HashSet values = new HashSet();
+ String type = readAttType(acc, values);
+ if (validating)
+ {
+ if ("ID".equals(type))
+ {
+ // VC: One ID per Element Type
+ for (Iterator i = doctype.attlistIterator(elementName);
+ i.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ AttributeDecl decl = (AttributeDecl) entry.getValue();
+ if ("ID".equals(decl.type))
+ error("element types must not have more than one ID " +
+ "attribute");
+ }
+ }
+ else if ("NOTATION".equals(type))
+ {
+ // VC: One Notation Per Element Type
+ for (Iterator i = doctype.attlistIterator(elementName);
+ i.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ AttributeDecl decl = (AttributeDecl) entry.getValue();
+ if ("NOTATION".equals(decl.type))
+ error("element types must not have more than one NOTATION " +
+ "attribute");
+ }
+ // VC: No Notation on Empty Element
+ ContentModel model = doctype.getElementModel(elementName);
+ if (model != null && model.type == ContentModel.EMPTY)
+ error("attributes of type NOTATION must not be declared on an " +
+ "element declared EMPTY");
+ }
+ }
+ String enumer = null;
+ if ("ENUMERATION".equals(type) || "NOTATION".equals(type))
+ enumer = acc.toString();
+ else
+ values = null;
+ requireWhitespace();
+ readDefault(elementName, name, type, enumer, values);
+ }
+
+ /**
+ * Parse an attribute type.
+ */
+ private String readAttType(StringBuffer acc, HashSet values)
+ throws IOException, XMLStreamException
+ {
+ if (tryRead('('))
+ {
+ readEnumeration(false, acc, values);
+ return "ENUMERATION";
+ }
+ else
+ {
+ String typeString = readNmtoken(true);
+ if ("NOTATION".equals(typeString))
+ {
+ readNotationType(acc, values);
+ return typeString;
+ }
+ else if ("CDATA".equals(typeString) ||
+ "ID".equals(typeString) ||
+ "IDREF".equals(typeString) ||
+ "IDREFS".equals(typeString) ||
+ "ENTITY".equals(typeString) ||
+ "ENTITIES".equals(typeString) ||
+ "NMTOKEN".equals(typeString) ||
+ "NMTOKENS".equals(typeString))
+ return typeString;
+ else
+ {
+ error("illegal attribute type", typeString);
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Parse an enumeration.
+ */
+ private void readEnumeration(boolean isNames, StringBuffer acc,
+ HashSet values)
+ throws IOException, XMLStreamException
+ {
+ acc.append('(');
+ // first token
+ skipWhitespace();
+ String token = readNmtoken(isNames);
+ acc.append(token);
+ values.add(token);
+ // subsequent tokens
+ skipWhitespace();
+ while (!tryRead(')'))
+ {
+ require('|');
+ acc.append('|');
+ skipWhitespace();
+ token = readNmtoken(isNames);
+ // VC: No Duplicate Tokens
+ if (validating && values.contains(token))
+ error("duplicate token", token);
+ acc.append(token);
+ values.add(token);
+ skipWhitespace();
+ }
+ acc.append(')');
+ }
+
+ /**
+ * Parse a notation type for an attribute.
+ */
+ private void readNotationType(StringBuffer acc, HashSet values)
+ throws IOException, XMLStreamException
+ {
+ requireWhitespace();
+ require('(');
+ readEnumeration(true, acc, values);
+ }
+
+ /**
+ * Parse the default value for an attribute.
+ */
+ private void readDefault(String elementName, String name,
+ String type, String enumeration, HashSet values)
+ throws IOException, XMLStreamException
+ {
+ int valueType = ATTRIBUTE_DEFAULT_SPECIFIED;
+ int flags = LIT_ATTRIBUTE;
+ String value = null, defaultType = null;
+ boolean saved = expandPE;
+
+ if (!"CDATA".equals(type))
+ flags |= LIT_NORMALIZE;
+
+ expandPE = false;
+ if (tryRead('#'))
+ {
+ if (tryRead("FIXED"))
+ {
+ defaultType = "#FIXED";
+ valueType = ATTRIBUTE_DEFAULT_FIXED;
+ requireWhitespace();
+ value = readLiteral(flags, false);
+ }
+ else if (tryRead("REQUIRED"))
+ {
+ defaultType = "#REQUIRED";
+ valueType = ATTRIBUTE_DEFAULT_REQUIRED;
+ }
+ else if (tryRead("IMPLIED"))
+ {
+ defaultType = "#IMPLIED";
+ valueType = ATTRIBUTE_DEFAULT_IMPLIED;
+ }
+ else
+ error("illegal keyword for attribute default value");
+ }
+ else
+ value = readLiteral(flags, false);
+ expandPE = saved;
+ if (validating)
+ {
+ if ("ID".equals(type))
+ {
+ // VC: Attribute Default Value Syntactically Correct
+ if (value != null && !isNmtoken(value, true))
+ error("default value must match Name production", value);
+ // VC: ID Attribute Default
+ if (valueType != ATTRIBUTE_DEFAULT_REQUIRED &&
+ valueType != ATTRIBUTE_DEFAULT_IMPLIED)
+ error("ID attributes must have a declared default of " +
+ "#IMPLIED or #REQUIRED");
+ }
+ else if (value != null)
+ {
+ // VC: Attribute Default Value Syntactically Correct
+ if ("IDREF".equals(type) || "ENTITY".equals(type))
+ {
+ if (!isNmtoken(value, true))
+ error("default value must match Name production", value);
+ }
+ else if ("IDREFS".equals(type) || "ENTITIES".equals(type))
+ {
+ StringTokenizer st = new StringTokenizer(value);
+ while (st.hasMoreTokens())
+ {
+ String token = st.nextToken();
+ if (!isNmtoken(token, true))
+ error("default value must match Name production", token);
+ }
+ }
+ else if ("NMTOKEN".equals(type) || "ENUMERATION".equals(type))
+ {
+ if (!isNmtoken(value, false))
+ error("default value must match Nmtoken production", value);
+ }
+ else if ("NMTOKENS".equals(type))
+ {
+ StringTokenizer st = new StringTokenizer(value);
+ while (st.hasMoreTokens())
+ {
+ String token = st.nextToken();
+ if (!isNmtoken(token, false))
+ error("default value must match Nmtoken production",
+ token);
+ }
+ }
+ }
+ }
+ // Register attribute def
+ AttributeDecl attribute =
+ new AttributeDecl(type, value, valueType, enumeration, values,
+ inputStack.size() != 1);
+ doctype.addAttributeDecl(elementName, name, attribute);
+ }
+
+ /**
+ * Parse the EntityDecl production.
+ */
+ private void readEntityDecl(boolean inExternalSubset)
+ throws IOException, XMLStreamException
+ {
+ int flags = 0;
+ // Check if parameter entity
+ boolean peFlag = false;
+ expandPE = false;
+ requireWhitespace();
+ if (tryRead('%'))
+ {
+ peFlag = true;
+ requireWhitespace();
+ }
+ expandPE = true;
+ // Read entity name
+ String name = readNmtoken(true);
+ if (name.indexOf(':') != -1)
+ error("illegal character ':' in entity name", name);
+ if (peFlag)
+ name = "%" + name;
+ requireWhitespace();
+ mark(1);
+ int c = readCh();
+ reset();
+ if (c == 0x22 || c == 0x27) // " | '
+ {
+ // Internal entity replacement text
+ String value = readLiteral(flags | LIT_DISABLE_EREF, true);
+ int ai = value.indexOf('&');
+ while (ai != -1)
+ {
+ int sci = value.indexOf(';', ai);
+ if (sci == -1)
+ error("malformed reference in entity value", value);
+ String ref = value.substring(ai + 1, sci);
+ int[] cp = UnicodeReader.toCodePointArray(ref);
+ if (cp.length == 0)
+ error("malformed reference in entity value", value);
+ if (cp[0] == 0x23) // #
+ {
+ if (cp.length == 1)
+ error("malformed reference in entity value", value);
+ if (cp[1] == 0x78) // 'x'
+ {
+ if (cp.length == 2)
+ error("malformed reference in entity value", value);
+ for (int i = 2; i < cp.length; i++)
+ {
+ int x = cp[i];
+ if (x < 0x30 ||
+ (x > 0x39 && x < 0x41) ||
+ (x > 0x46 && x < 0x61) ||
+ x > 0x66)
+ error("malformed character reference in entity value",
+ value);
+ }
+ }
+ else
+ {
+ for (int i = 1; i < cp.length; i++)
+ {
+ int x = cp[i];
+ if (x < 0x30 || x > 0x39)
+ error("malformed character reference in entity value",
+ value);
+ }
+ }
+ }
+ else
+ {
+ if (!isNameStartCharacter(cp[0]))
+ error("malformed reference in entity value", value);
+ for (int i = 1; i < cp.length; i++)
+ {
+ if (!isNameCharacter(cp[i]))
+ error("malformed reference in entity value", value);
+ }
+ }
+ ai = value.indexOf('&', sci);
+ }
+ doctype.addEntityDecl(name, value, inExternalSubset);
+ }
+ else
+ {
+ ExternalIds ids = readExternalIds(false, false);
+ // Check for NDATA
+ boolean white = tryWhitespace();
+ if (!peFlag && tryRead("NDATA"))
+ {
+ if (!white)
+ error("whitespace required before NDATA");
+ requireWhitespace();
+ ids.notationName = readNmtoken(true);
+ }
+ doctype.addEntityDecl(name, ids, inExternalSubset);
+ }
+ // finish
+ skipWhitespace();
+ require('>');
+ }
+
+ /**
+ * Parse the NotationDecl production.
+ */
+ private void readNotationDecl(boolean inExternalSubset)
+ throws IOException, XMLStreamException
+ {
+ requireWhitespace();
+ String notationName = readNmtoken(true);
+ if (notationName.indexOf(':') != -1)
+ error("illegal character ':' in notation name", notationName);
+ if (validating)
+ {
+ // VC: Unique Notation Name
+ ExternalIds notation = doctype.getNotation(notationName);
+ if (notation != null)
+ error("duplicate notation name", notationName);
+ }
+ requireWhitespace();
+ ExternalIds ids = readExternalIds(true, false);
+ ids.notationName = notationName;
+ doctype.addNotationDecl(notationName, ids, inExternalSubset);
+ skipWhitespace();
+ require('>');
+ }
+
+ /**
+ * Returns a tuple {publicId, systemId}.
+ */
+ private ExternalIds readExternalIds(boolean inNotation, boolean isSubset)
+ throws IOException, XMLStreamException
+ {
+ int c;
+ int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF;
+ ExternalIds ids = new ExternalIds();
+
+ if (tryRead("PUBLIC"))
+ {
+ requireWhitespace();
+ ids.publicId = readLiteral(LIT_NORMALIZE | LIT_PUBID | flags, false);
+ if (inNotation)
+ {
+ skipWhitespace();
+ mark(1);
+ c = readCh();
+ reset();
+ if (c == 0x22 || c == 0x27) // " | '
+ {
+ String href = readLiteral(flags, false);
+ ids.systemId = absolutize(input.systemId, href);
+ }
+ }
+ else
+ {
+ requireWhitespace();
+ String href = readLiteral(flags, false);
+ ids.systemId = absolutize(input.systemId, href);
+ }
+ // Check valid URI characters
+ for (int i = 0; i < ids.publicId.length(); i++)
+ {
+ char d = ids.publicId.charAt(i);
+ if (d >= 'a' && d <= 'z')
+ continue;
+ if (d >= 'A' && d <= 'Z')
+ continue;
+ if (" \r\n0123456789-' ()+,./:=?;!*#@$_%".indexOf(d) != -1)
+ continue;
+ error("illegal PUBLIC id character",
+ "U+" + Integer.toHexString(d));
+ }
+ }
+ else if (tryRead("SYSTEM"))
+ {
+ requireWhitespace();
+ String href = readLiteral(flags, false);
+ ids.systemId = absolutize(input.systemId, href);
+ }
+ else if (!isSubset)
+ {
+ error("missing SYSTEM or PUBLIC keyword");
+ }
+ if (ids.systemId != null && !inNotation)
+ {
+ if (ids.systemId.indexOf('#') != -1)
+ error("SYSTEM id has a URI fragment", ids.systemId);
+ }
+ return ids;
+ }
+
+ /**
+ * Parse the start of an element.
+ * @return the state of the parser afterwards (EMPTY_ELEMENT or CONTENT)
+ */
+ private int readStartElement()
+ throws IOException, XMLStreamException
+ {
+ // Read element name
+ String elementName = readNmtoken(true);
+ attrs.clear();
+ // Push namespace context
+ if (namespaceAware)
+ {
+ if (elementName.charAt(0) == ':' ||
+ elementName.charAt(elementName.length() - 1) == ':')
+ error("not a QName", elementName);
+ namespaces.addFirst(new LinkedHashMap());
+ }
+ // Read element content
+ boolean white = tryWhitespace();
+ mark(1);
+ int c = readCh();
+ while (c != 0x2f && c != 0x3e) // '/' | '>'
+ {
+ // Read attribute
+ reset();
+ if (!white)
+ error("need whitespace between attributes");
+ readAttribute(elementName);
+ white = tryWhitespace();
+ mark(1);
+ c = readCh();
+ }
+ // supply defaulted attributes
+ if (doctype != null)
+ {
+ for (Iterator i = doctype.attlistIterator(elementName); i.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ String attName = (String) entry.getKey();
+ AttributeDecl decl = (AttributeDecl) entry.getValue();
+ if (validating)
+ {
+ switch (decl.valueType)
+ {
+ case ATTRIBUTE_DEFAULT_REQUIRED:
+ // VC: Required Attribute
+ if (decl.value == null && !attributeSpecified(attName))
+ error("value for " + attName + " attribute is required");
+ break;
+ case ATTRIBUTE_DEFAULT_FIXED:
+ // VC: Fixed Attribute Default
+ for (Iterator j = attrs.iterator(); j.hasNext(); )
+ {
+ Attribute a = (Attribute) j.next();
+ if (attName.equals(a.name) &&
+ !decl.value.equals(a.value))
+ error("value for " + attName + " attribute must be " +
+ decl.value);
+ }
+ break;
+ }
+ }
+ if (namespaceAware && attName.equals("xmlns"))
+ {
+ LinkedHashMap ctx =
+ (LinkedHashMap) namespaces.getFirst();
+ if (ctx.containsKey(XMLConstants.DEFAULT_NS_PREFIX))
+ continue; // namespace was specified
+ }
+ else if (namespaceAware && attName.startsWith("xmlns:"))
+ {
+ LinkedHashMap ctx =
+ (LinkedHashMap) namespaces.getFirst();
+ if (ctx.containsKey(attName.substring(6)))
+ continue; // namespace was specified
+ }
+ else if (attributeSpecified(attName))
+ continue;
+ if (decl.value == null)
+ continue;
+ // VC: Standalone Document Declaration
+ if (validating && decl.external && xmlStandalone == Boolean.TRUE)
+ error("standalone must be 'no' if attributes inherit values " +
+ "from externally declared markup declarations");
+ Attribute attr =
+ new Attribute(attName, decl.type, false, decl.value);
+ if (namespaceAware)
+ {
+ if (!addNamespace(attr))
+ attrs.add(attr);
+ }
+ else
+ attrs.add(attr);
+ }
+ }
+ if (baseAware)
+ {
+ String uri = getAttributeValue(XMLConstants.XML_NS_URI, "base");
+ String base = getXMLBase();
+ bases.addFirst(absolutize(base, uri));
+ }
+ if (namespaceAware)
+ {
+ // check prefix bindings
+ int ci = elementName.indexOf(':');
+ if (ci != -1)
+ {
+ String prefix = elementName.substring(0, ci);
+ String uri = getNamespaceURI(prefix);
+ if (uri == null)
+ error("unbound element prefix", prefix);
+ else if (input.xml11 && "".equals(uri))
+ error("XML 1.1 unbound element prefix", prefix);
+ }
+ for (Iterator i = attrs.iterator(); i.hasNext(); )
+ {
+ Attribute attr = (Attribute) i.next();
+ if (attr.prefix != null &&
+ !XMLConstants.XMLNS_ATTRIBUTE.equals(attr.prefix))
+ {
+ String uri = getNamespaceURI(attr.prefix);
+ if (uri == null)
+ error("unbound attribute prefix", attr.prefix);
+ else if (input.xml11 && "".equals(uri))
+ error("XML 1.1 unbound attribute prefix", attr.prefix);
+ }
+ }
+ }
+ if (validating && doctype != null)
+ {
+ validateStartElement(elementName);
+ currentContentModel = doctype.getElementModel(elementName);
+ if (currentContentModel == null)
+ error("no element declaration", elementName);
+ validationStack.add(new LinkedList());
+ }
+ // make element name available for read
+ buf.setLength(0);
+ buf.append(elementName);
+ // push element onto stack
+ stack.addLast(elementName);
+ switch (c)
+ {
+ case 0x3e: // '>'
+ return CONTENT;
+ case 0x2f: // '/'
+ require('>');
+ return EMPTY_ELEMENT;
+ }
+ return -1; // to satisfy compiler
+ }
+
+ /**
+ * Indicates whether the specified attribute name was specified for the
+ * current element.
+ */
+ private boolean attributeSpecified(String attName)
+ {
+ for (Iterator j = attrs.iterator(); j.hasNext(); )
+ {
+ Attribute a = (Attribute) j.next();
+ if (attName.equals(a.name))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Parse an attribute.
+ */
+ private void readAttribute(String elementName)
+ throws IOException, XMLStreamException
+ {
+ // Read attribute name
+ String attributeName = readNmtoken(true);
+ String type = getAttributeType(elementName, attributeName);
+ readEq();
+ // Read literal
+ final int flags = LIT_ATTRIBUTE | LIT_ENTITY_REF;
+ String value = (type == null || "CDATA".equals(type)) ?
+ readLiteral(flags, false) : readLiteral(flags | LIT_NORMALIZE, false);
+ // add attribute event
+ Attribute attr = this.new Attribute(attributeName, type, true, value);
+ if (namespaceAware)
+ {
+ if (attributeName.charAt(0) == ':' ||
+ attributeName.charAt(attributeName.length() - 1) == ':')
+ error("not a QName", attributeName);
+ else if (attributeName.equals("xmlns"))
+ {
+ LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst();
+ if (ctx.containsKey(XMLConstants.DEFAULT_NS_PREFIX))
+ error("duplicate default namespace");
+ }
+ else if (attributeName.startsWith("xmlns:"))
+ {
+ LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst();
+ if (ctx.containsKey(attributeName.substring(6)))
+ error("duplicate namespace", attributeName.substring(6));
+ }
+ else if (attrs.contains(attr))
+ error("duplicate attribute", attributeName);
+ }
+ else if (attrs.contains(attr))
+ error("duplicate attribute", attributeName);
+ if (validating && doctype != null)
+ {
+ // VC: Attribute Value Type
+ AttributeDecl decl =
+ doctype.getAttributeDecl(elementName, attributeName);
+ if (decl == null)
+ error("attribute must be declared", attributeName);
+ if ("ENUMERATION".equals(decl.type))
+ {
+ // VC: Enumeration
+ if (!decl.values.contains(value))
+ error("value does not match enumeration " + decl.enumeration,
+ value);
+ }
+ else if ("ID".equals(decl.type))
+ {
+ // VC: ID
+ if (!isNmtoken(value, true))
+ error("ID values must match the Name production");
+ if (ids.contains(value))
+ error("Duplicate ID", value);
+ ids.add(value);
+ }
+ else if ("IDREF".equals(decl.type) || "IDREFS".equals(decl.type))
+ {
+ StringTokenizer st = new StringTokenizer(value);
+ while (st.hasMoreTokens())
+ {
+ String token = st.nextToken();
+ // VC: IDREF
+ if (!isNmtoken(token, true))
+ error("IDREF values must match the Name production");
+ idrefs.add(token);
+ }
+ }
+ else if ("NMTOKEN".equals(decl.type) || "NMTOKENS".equals(decl.type))
+ {
+ StringTokenizer st = new StringTokenizer(value);
+ while (st.hasMoreTokens())
+ {
+ String token = st.nextToken();
+ // VC: Name Token
+ if (!isNmtoken(token, false))
+ error("NMTOKEN values must match the Nmtoken production");
+ }
+ }
+ else if ("ENTITY".equals(decl.type))
+ {
+ // VC: Entity Name
+ if (!isNmtoken(value, true))
+ error("ENTITY values must match the Name production");
+ Object entity = doctype.getEntity(value);
+ if (entity == null || !(entity instanceof ExternalIds) ||
+ ((ExternalIds) entity).notationName == null)
+ error("ENTITY values must match the name of an unparsed " +
+ "entity declared in the DTD");
+ }
+ else if ("NOTATION".equals(decl.type))
+ {
+ if (!decl.values.contains(value))
+ error("NOTATION values must match a declared notation name",
+ value);
+ // VC: Notation Attributes
+ ExternalIds notation = doctype.getNotation(value);
+ if (notation == null)
+ error("NOTATION values must match the name of a notation " +
+ "declared in the DTD", value);
+ }
+ }
+ if (namespaceAware)
+ {
+ if (!addNamespace(attr))
+ attrs.add(attr);
+ }
+ else
+ attrs.add(attr);
+ }
+
+ /**
+ * Determines whether the specified attribute is a namespace declaration,
+ * and adds it to the current namespace context if so. Returns false if
+ * the attribute is an ordinary attribute.
+ */
+ private boolean addNamespace(Attribute attr)
+ throws XMLStreamException
+ {
+ if ("xmlns".equals(attr.name))
+ {
+ LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst();
+ if (ctx.get(XMLConstants.DEFAULT_NS_PREFIX) != null)
+ error("Duplicate default namespace declaration");
+ if (XMLConstants.XML_NS_URI.equals(attr.value))
+ error("can't bind XML namespace");
+ if ("".equals(attr.value) && !input.xml11)
+ error("illegal use of 1.1-style prefix unbinding in 1.0 document");
+ ctx.put(XMLConstants.DEFAULT_NS_PREFIX, attr.value);
+ return true;
+ }
+ else if ("xmlns".equals(attr.prefix))
+ {
+ LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst();
+ if (ctx.get(attr.localName) != null)
+ error("Duplicate namespace declaration for prefix",
+ attr.localName);
+ if (XMLConstants.XML_NS_PREFIX.equals(attr.localName))
+ {
+ if (!XMLConstants.XML_NS_URI.equals(attr.value))
+ error("can't redeclare xml prefix");
+ else
+ return false; // treat as attribute
+ }
+ if (XMLConstants.XML_NS_URI.equals(attr.value))
+ error("can't bind non-xml prefix to XML namespace");
+ if (XMLConstants.XMLNS_ATTRIBUTE.equals(attr.localName))
+ error("can't redeclare xmlns prefix");
+ if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(attr.value))
+ error("can't bind non-xmlns prefix to XML Namespace namespace");
+ if ("".equals(attr.value) && !input.xml11)
+ error("illegal use of 1.1-style prefix unbinding in 1.0 document");
+ ctx.put(attr.localName, attr.value);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Parse a closing tag.
+ */
+ private void readEndElement()
+ throws IOException, XMLStreamException
+ {
+ // pop element off stack
+ String expected = (String) stack.removeLast();
+ require(expected);
+ skipWhitespace();
+ require('>');
+ // Make element name available
+ buf.setLength(0);
+ buf.append(expected);
+ if (validating && doctype != null)
+ endElementValidationHook();
+ }
+
+ /**
+ * Validate the end of an element.
+ * Called on an end-element or empty element if validating.
+ */
+ private void endElementValidationHook()
+ throws XMLStreamException
+ {
+ validateEndElement();
+ validationStack.removeLast();
+ if (stack.isEmpty())
+ currentContentModel = null;
+ else
+ {
+ String parent = (String) stack.getLast();
+ currentContentModel = doctype.getElementModel(parent);
+ }
+ }
+
+ /**
+ * Parse a comment.
+ */
+ private void readComment(boolean inDTD)
+ throws IOException, XMLStreamException
+ {
+ boolean saved = expandPE;
+ expandPE = false;
+ buf.setLength(0);
+ readUntil(TEST_END_COMMENT);
+ require('>');
+ expandPE = saved;
+ if (inDTD)
+ doctype.addComment(buf.toString());
+ }
+
+ /**
+ * Parse a processing instruction.
+ */
+ private void readPI(boolean inDTD)
+ throws IOException, XMLStreamException
+ {
+ boolean saved = expandPE;
+ expandPE = false;
+ piTarget = readNmtoken(true);
+ if (piTarget.indexOf(':') != -1)
+ error("illegal character in PI target", new Character(':'));
+ if ("xml".equalsIgnoreCase(piTarget))
+ error("illegal PI target", piTarget);
+ if (tryRead(TEST_END_PI))
+ piData = null;
+ else
+ {
+ if (!tryWhitespace())
+ error("whitespace required between PI target and data");
+ buf.setLength(0);
+ readUntil(TEST_END_PI);
+ piData = buf.toString();
+ }
+ expandPE = saved;
+ if (inDTD)
+ doctype.addPI(piTarget, piData);
+ }
+
+ /**
+ * Parse an entity reference.
+ */
+ private void readReference()
+ throws IOException, XMLStreamException
+ {
+ buf.setLength(0);
+ String entityName = readNmtoken(true);
+ require(';');
+ buf.setLength(0);
+ buf.append(entityName);
+ }
+
+ /**
+ * Read an CDATA section.
+ */
+ private void readCDSect()
+ throws IOException, XMLStreamException
+ {
+ buf.setLength(0);
+ readUntil(TEST_END_CDATA);
+ }
+
+ /**
+ * Read character data.
+ * @return the type of text read (CHARACTERS or SPACE)
+ */
+ private int readCharData(String prefix)
+ throws IOException, XMLStreamException
+ {
+ boolean white = true;
+ buf.setLength(0);
+ if (prefix != null)
+ buf.append(prefix);
+ boolean done = false;
+ boolean entities = false;
+ while (!done)
+ {
+ // Block read
+ mark(tmpBuf.length);
+ int len = read(tmpBuf, 0, tmpBuf.length);
+ if (len == -1)
+ {
+ if (inputStack.size() > 1)
+ {
+ popInput();
+ // report end-entity
+ done = true;
+ }
+ else
+ throw new EOFException();
+ }
+ for (int i = 0; i < len && !done; i++)
+ {
+ int c = tmpBuf[i];
+ switch (c)
+ {
+ case 0x20:
+ case 0x09:
+ case 0x0a:
+ case 0x0d:
+ buf.append(Character.toChars(c));
+ break; // whitespace
+ case 0x26: // '&'
+ reset();
+ read(tmpBuf, 0, i);
+ // character reference?
+ mark(3);
+ c = readCh(); // &
+ c = readCh();
+ if (c == 0x23) // '#'
+ {
+ mark(1);
+ c = readCh();
+ boolean hex = (c == 0x78); // 'x'
+ if (!hex)
+ reset();
+ char[] ch = readCharacterRef(hex ? 16 : 10);
+ buf.append(ch, 0, ch.length);
+ for (int j = 0; j < ch.length; j++)
+ {
+ switch (ch[j])
+ {
+ case 0x20:
+ case 0x09:
+ case 0x0a:
+ case 0x0d:
+ break; // whitespace
+ default:
+ white = false;
+ }
+ }
+ }
+ else
+ {
+ // entity reference
+ reset();
+ c = readCh(); // &
+ String entityName = readNmtoken(true);
+ require(';');
+ String text =
+ (String) PREDEFINED_ENTITIES.get(entityName);
+ if (text != null)
+ buf.append(text);
+ else
+ {
+ pushInput("", "&" + entityName + ";", false, false);
+ done = true;
+ break;
+ }
+ }
+ // continue processing
+ i = -1;
+ mark(tmpBuf.length);
+ len = read(tmpBuf, 0, tmpBuf.length);
+ if (len == -1)
+ {
+ if (inputStack.size() > 1)
+ {
+ popInput();
+ done = true;
+ }
+ else
+ throw new EOFException();
+ }
+ entities = true;
+ break; // end of text sequence
+ case 0x3e: // '>'
+ int l = buf.length();
+ if (l > 1 &&
+ buf.charAt(l - 1) == ']' &&
+ buf.charAt(l - 2) == ']')
+ error("Character data may not contain unescaped ']]>'");
+ buf.append(Character.toChars(c));
+ break;
+ case 0x3c: // '<'
+ reset();
+ read(tmpBuf, 0, i);
+ i = len;
+ if (coalescing && tryRead(TEST_CDATA))
+ readUntil(TEST_END_CDATA); // read CDATA section into buf
+ else
+ done = true; // end of text sequence
+ break;
+ default:
+ if (input.xml11)
+ {
+ if (!isXML11Char(c) || isXML11RestrictedChar(c))
+ error("illegal XML 1.1 character",
+ "U+" + Integer.toHexString(c));
+ }
+ else if (!isChar(c))
+ error("illegal XML character",
+ "U+" + Integer.toHexString(c));
+ white = false;
+ buf.append(Character.toChars(c));
+ }
+ }
+ // if text buffer >= 2MB, return it as a chunk
+ // to avoid excessive memory use
+ if (buf.length() >= 2097152)
+ done = true;
+ }
+ if (entities)
+ normalizeCRLF(buf);
+ return white ? XMLStreamConstants.SPACE : XMLStreamConstants.CHARACTERS;
+ }
+
+ /**
+ * Expands the specified entity.
+ */
+ private void expandEntity(String name, boolean inAttr, boolean normalize)
+ throws IOException, XMLStreamException
+ {
+ if (doctype != null)
+ {
+ Object value = doctype.getEntity(name);
+ if (value != null)
+ {
+ if (xmlStandalone == Boolean.TRUE)
+ {
+ // VC: Standalone Document Declaration
+ if (doctype.isEntityExternal(name))
+ error("reference to external entity in standalone document");
+ else if (value instanceof ExternalIds)
+ {
+ ExternalIds ids = (ExternalIds) value;
+ if (ids.notationName != null &&
+ doctype.isNotationExternal(ids.notationName))
+ error("reference to external notation in " +
+ "standalone document");
+ }
+ }
+ if (value instanceof String)
+ {
+ String text = (String) value;
+ if (inAttr && text.indexOf('<') != -1)
+ error("< in attribute value");
+ pushInput(name, text, !inAttr, normalize);
+ }
+ else if (inAttr)
+ error("reference to external entity in attribute value", name);
+ else
+ pushInput(name, (ExternalIds) value, !inAttr, normalize);
+ return;
+ }
+ }
+ error("reference to undeclared entity", name);
+ }
+
+ /**
+ * Indicates whether the specified entity is unparsed.
+ */
+ private boolean isUnparsedEntity(String name)
+ {
+ if (doctype != null)
+ {
+ Object value = doctype.getEntity(name);
+ if (value != null && value instanceof ExternalIds)
+ return ((ExternalIds) value).notationName != null;
+ }
+ return false;
+ }
+
+ /**
+ * Read an equals sign.
+ */
+ private void readEq()
+ throws IOException, XMLStreamException
+ {
+ skipWhitespace();
+ require('=');
+ skipWhitespace();
+ }
+
+ /**
+ * Character read for reading literals.
+ * @param recognizePEs whether to recognize parameter-entity references
+ */
+ private int literalReadCh(boolean recognizePEs)
+ throws IOException, XMLStreamException
+ {
+ int c = recognizePEs ? readCh() : read();
+ while (c == -1)
+ {
+ if (inputStack.size() > 1)
+ {
+ inputStack.removeLast();
+ input = (Input) inputStack.getLast();
+ // Don't issue end-entity
+ c = recognizePEs ? readCh() : read();
+ }
+ else
+ throw new EOFException();
+ }
+ return c;
+ }
+
+ /**
+ * Read a string literal.
+ */
+ private String readLiteral(int flags, boolean recognizePEs)
+ throws IOException, XMLStreamException
+ {
+ boolean saved = expandPE;
+ int delim = readCh();
+ if (delim != 0x27 && delim != 0x22)
+ error("expected '\"' or \"'\"", "U+" + Integer.toHexString(delim));
+ literalBuf.setLength(0);
+ if ((flags & LIT_DISABLE_PE) != 0)
+ expandPE = false;
+ boolean entities = false;
+ int inputStackSize = inputStack.size();
+ do
+ {
+ int c = literalReadCh(recognizePEs);
+ if (c == delim && inputStackSize == inputStack.size())
+ break;
+ switch (c)
+ {
+ case 0x0a:
+ case 0x0d:
+ if ((flags & (LIT_ATTRIBUTE | LIT_PUBID)) != 0)
+ c = 0x20; // normalize to space
+ break;
+ case 0x09:
+ if ((flags & LIT_ATTRIBUTE) != 0)
+ c = 0x20; // normalize to space
+ break;
+ case 0x26: // '&'
+ mark(2);
+ c = readCh();
+ if (c == 0x23) // '#'
+ {
+ if ((flags & LIT_DISABLE_CREF) != 0)
+ {
+ reset();
+ c = 0x26; // '&'
+ }
+ else
+ {
+ mark(1);
+ c = readCh();
+ boolean hex = (c == 0x78); // 'x'
+ if (!hex)
+ reset();
+ char[] ref = readCharacterRef(hex ? 16 : 10);
+ for (int i = 0; i < ref.length; i++)
+ {
+ char x = ref[i];
+ if ((flags & (LIT_ATTRIBUTE | LIT_PUBID)) != 0 &&
+ (x == 0x0a || x == 0x0d))
+ x = 0x20; // normalize
+ else if ((flags & LIT_ATTRIBUTE) != 0 && x == 0x09)
+ x = 0x20; // normalize
+ literalBuf.append(x);
+ }
+ entities = true;
+ continue;
+ }
+ }
+ else
+ {
+ if ((flags & LIT_DISABLE_EREF) != 0)
+ {
+ reset();
+ c = 0x26; // '&'
+ }
+ else
+ {
+ reset();
+ String entityName = readNmtoken(true);
+ require(';');
+ String text =
+ (String) PREDEFINED_ENTITIES.get(entityName);
+ if (text != null)
+ literalBuf.append(text);
+ else
+ expandEntity(entityName,
+ (flags & LIT_ATTRIBUTE) != 0,
+ true);
+ entities = true;
+ continue;
+ }
+ }
+ break;
+ case 0x3c: // '<'
+ if ((flags & LIT_ATTRIBUTE) != 0)
+ error("attribute values may not contain '<'");
+ break;
+ case -1:
+ if (inputStack.size() > 1)
+ {
+ popInput();
+ continue;
+ }
+ throw new EOFException();
+ default:
+ if ((c < 0x0020 || c > 0xfffd) ||
+ (c >= 0xd800 && c < 0xdc00) ||
+ (input.xml11 && (c >= 0x007f) &&
+ (c <= 0x009f) && (c != 0x0085)))
+ error("illegal character", "U+" + Integer.toHexString(c));
+ }
+ literalBuf.append(Character.toChars(c));
+ }
+ while (true);
+ expandPE = saved;
+ if (entities)
+ normalizeCRLF(literalBuf);
+ if ((flags & LIT_NORMALIZE) > 0)
+ literalBuf = normalize(literalBuf);
+ return literalBuf.toString();
+ }
+
+ /**
+ * Performs attribute-value normalization of the text buffer.
+ * This discards leading and trailing whitespace, and replaces sequences
+ * of whitespace with a single space.
+ */
+ private StringBuffer normalize(StringBuffer buf)
+ {
+ StringBuffer acc = new StringBuffer();
+ int len = buf.length();
+ int avState = 0;
+ for (int i = 0; i < len; i++)
+ {
+ char c = buf.charAt(i);
+ if (c == ' ')
+ avState = (avState == 0) ? 0 : 1;
+ else
+ {
+ if (avState == 1)
+ acc.append(' ');
+ acc.append(c);
+ avState = 2;
+ }
+ }
+ return acc;
+ }
+
+ /**
+ * Replace any CR/LF pairs in the buffer with LF.
+ * This may be necessary if combinations of CR or LF were declared as
+ * (character) entity references in the input.
+ */
+ private void normalizeCRLF(StringBuffer buf)
+ {
+ int len = buf.length() - 1;
+ for (int i = 0; i < len; i++)
+ {
+ char c = buf.charAt(i);
+ if (c == '\r' && buf.charAt(i + 1) == '\n')
+ {
+ buf.deleteCharAt(i--);
+ len--;
+ }
+ }
+ }
+
+ /**
+ * Parse and expand a parameter entity reference.
+ */
+ private void expandPEReference()
+ throws IOException, XMLStreamException
+ {
+ String name = readNmtoken(true, new StringBuffer());
+ require(';');
+ mark(1); // ensure we don't reset to before the semicolon
+ if (doctype != null)
+ {
+ String entityName = "%" + name;
+ Object entity = doctype.getEntity(entityName);
+ if (entity != null)
+ {
+ if (xmlStandalone == Boolean.TRUE)
+ {
+ if (doctype.isEntityExternal(entityName))
+ error("reference to external parameter entity in " +
+ "standalone document");
+ }
+ if (entity instanceof String)
+ {
+ pushInput(name, (String) entity, false, input.normalize);
+ //pushInput(name, " " + (String) entity + " ");
+ }
+ else
+ {
+ //pushInput("", " ");
+ pushInput(name, (ExternalIds) entity, false, input.normalize);
+ //pushInput("", " ");
+ }
+ }
+ else
+ error("reference to undeclared parameter entity", name);
+ }
+ else
+ error("reference to parameter entity without doctype", name);
+ }
+
+ /**
+ * Parse the digits in a character reference.
+ * @param base the base of the digits (10 or 16)
+ */
+ private char[] readCharacterRef(int base)
+ throws IOException, XMLStreamException
+ {
+ StringBuffer b = new StringBuffer();
+ for (int c = readCh(); c != 0x3b && c != -1; c = readCh())
+ b.append(Character.toChars(c));
+ try
+ {
+ int ord = Integer.parseInt(b.toString(), base);
+ if (input.xml11)
+ {
+ if (!isXML11Char(ord))
+ error("illegal XML 1.1 character reference " +
+ "U+" + Integer.toHexString(ord));
+ }
+ else
+ {
+ if ((ord < 0x20 && !(ord == 0x0a || ord == 0x09 || ord == 0x0d))
+ || (ord >= 0xd800 && ord <= 0xdfff)
+ || ord == 0xfffe || ord == 0xffff
+ || ord > 0x0010ffff)
+ error("illegal XML character reference " +
+ "U+" + Integer.toHexString(ord));
+ }
+ return Character.toChars(ord);
+ }
+ catch (NumberFormatException e)
+ {
+ error("illegal characters in character reference", b.toString());
+ return null;
+ }
+ }
+
+ /**
+ * Parses an NMTOKEN or Name production.
+ * @param isName if a Name, otherwise an NMTOKEN
+ */
+ private String readNmtoken(boolean isName)
+ throws IOException, XMLStreamException
+ {
+ return readNmtoken(isName, nmtokenBuf);
+ }
+
+ /**
+ * Parses an NMTOKEN or Name production using the specified buffer.
+ * @param isName if a Name, otherwise an NMTOKEN
+ * @param buf the character buffer to use
+ */
+ private String readNmtoken(boolean isName, StringBuffer buf)
+ throws IOException, XMLStreamException
+ {
+ buf.setLength(0);
+ int c = readCh();
+ if (isName)
+ {
+ if (!isNameStartCharacter(c))
+ error("not a name start character",
+ "U+" + Integer.toHexString(c));
+ }
+ else
+ {
+ if (!isNameCharacter(c))
+ error("not a name character",
+ "U+" + Integer.toHexString(c));
+ }
+ buf.append(Character.toChars(c));
+ do
+ {
+ mark(1);
+ c = readCh();
+ switch (c)
+ {
+ case 0x25: // '%'
+ case 0x3c: // '<'
+ case 0x3e: // '>'
+ case 0x26: // '&'
+ case 0x2c: // ','
+ case 0x7c: // '|'
+ case 0x2a: // '*'
+ case 0x2b: // '+'
+ case 0x3f: // '?'
+ case 0x29: // ')'
+ case 0x3d: // '='
+ case 0x27: // '\''
+ case 0x22: // '"'
+ case 0x5b: // '['
+ case 0x20: // ' '
+ case 0x09: // '\t'
+ case 0x0a: // '\n'
+ case 0x0d: // '\r'
+ case 0x3b: // ';'
+ case 0x2f: // '/'
+ case -1:
+ reset();
+ return intern(buf.toString());
+ default:
+ if (!isNameCharacter(c))
+ error("not a name character",
+ "U+" + Integer.toHexString(c));
+ else
+ buf.append(Character.toChars(c));
+ }
+ }
+ while (true);
+ }
+
+ /**
+ * Indicates whether the specified Unicode character is an XML 1.1 Char.
+ */
+ private boolean isXML11Char(int c)
+ {
+ return ((c >= 0x0001 && c <= 0xD7FF) ||
+ (c >= 0xE000 && c < 0xFFFD) || // NB exclude 0xfffd
+ (c >= 0x10000 && c <= 0x10FFFF));
+ }
+
+ /**
+ * Indicates whether the specified Unicode character is an XML 1.1
+ * RestrictedChar.
+ */
+ private boolean isXML11RestrictedChar(int c)
+ {
+ return ((c >= 0x0001 && c <= 0x0008) ||
+ (c >= 0x000B && c <= 0x000C) ||
+ (c >= 0x000E && c <= 0x001F) ||
+ (c >= 0x007F && c <= 0x0084) ||
+ (c >= 0x0086 && c <= 0x009F));
+ }
+
+ /**
+ * Indicates whether the specified text matches the Name or Nmtoken
+ * production.
+ */
+ private boolean isNmtoken(String text, boolean isName)
+ {
+ try
+ {
+ int[] cp = UnicodeReader.toCodePointArray(text);
+ if (cp.length == 0)
+ return false;
+ if (isName)
+ {
+ if (!isNameStartCharacter(cp[0]))
+ return false;
+ }
+ else
+ {
+ if (!isNameCharacter(cp[0]))
+ return false;
+ }
+ for (int i = 1; i < cp.length; i++)
+ {
+ if (!isNameCharacter(cp[i]))
+ return false;
+ }
+ return true;
+ }
+ catch (IOException e)
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Indicates whether the specified Unicode character is a Name start
+ * character.
+ */
+ private boolean isNameStartCharacter(int c)
+ {
+ if (input.xml11)
+ return ((c >= 0x0041 && c <= 0x005a) ||
+ (c >= 0x0061 && c <= 0x007a) ||
+ c == 0x3a |
+ c == 0x5f |
+ (c >= 0xC0 && c <= 0xD6) ||
+ (c >= 0xD8 && c <= 0xF6) ||
+ (c >= 0xF8 && c <= 0x2FF) ||
+ (c >= 0x370 && c <= 0x37D) ||
+ (c >= 0x37F && c <= 0x1FFF) ||
+ (c >= 0x200C && c <= 0x200D) ||
+ (c >= 0x2070 && c <= 0x218F) ||
+ (c >= 0x2C00 && c <= 0x2FEF) ||
+ (c >= 0x3001 && c <= 0xD7FF) ||
+ (c >= 0xF900 && c <= 0xFDCF) ||
+ (c >= 0xFDF0 && c <= 0xFFFD) ||
+ (c >= 0x10000 && c <= 0xEFFFF));
+ else
+ return (c == 0x5f || c == 0x3a || isLetter(c));
+ }
+
+ /**
+ * Indicates whether the specified Unicode character is a Name non-initial
+ * character.
+ */
+ private boolean isNameCharacter(int c)
+ {
+ if (input.xml11)
+ return ((c >= 0x0041 && c <= 0x005a) ||
+ (c >= 0x0061 && c <= 0x007a) ||
+ (c >= 0x0030 && c <= 0x0039) ||
+ c == 0x3a |
+ c == 0x5f |
+ c == 0x2d |
+ c == 0x2e |
+ c == 0xB7 |
+ (c >= 0xC0 && c <= 0xD6) ||
+ (c >= 0xD8 && c <= 0xF6) ||
+ (c >= 0xF8 && c <= 0x2FF) ||
+ (c >= 0x300 && c <= 0x37D) ||
+ (c >= 0x37F && c <= 0x1FFF) ||
+ (c >= 0x200C && c <= 0x200D) ||
+ (c >= 0x203F && c <= 0x2040) ||
+ (c >= 0x2070 && c <= 0x218F) ||
+ (c >= 0x2C00 && c <= 0x2FEF) ||
+ (c >= 0x3001 && c <= 0xD7FF) ||
+ (c >= 0xF900 && c <= 0xFDCF) ||
+ (c >= 0xFDF0 && c <= 0xFFFD) ||
+ (c >= 0x10000 && c <= 0xEFFFF));
+ else
+ return (c == 0x2e || c == 0x2d || c == 0x5f || c == 0x3a ||
+ isLetter(c) || isDigit(c) ||
+ isCombiningChar(c) || isExtender(c));
+ }
+
+ /**
+ * Indicates whether the specified Unicode character matches the Letter
+ * production.
+ */
+ public static boolean isLetter(int c)
+ {
+ if ((c >= 0x0041 && c <= 0x005A) ||
+ (c >= 0x0061 && c <= 0x007A) ||
+ (c >= 0x00C0 && c <= 0x00D6) ||
+ (c >= 0x00D8 && c <= 0x00F6) ||
+ (c >= 0x00F8 && c <= 0x00FF) ||
+ (c >= 0x0100 && c <= 0x0131) ||
+ (c >= 0x0134 && c <= 0x013E) ||
+ (c >= 0x0141 && c <= 0x0148) ||
+ (c >= 0x014A && c <= 0x017E) ||
+ (c >= 0x0180 && c <= 0x01C3) ||
+ (c >= 0x01CD && c <= 0x01F0) ||
+ (c >= 0x01F4 && c <= 0x01F5) ||
+ (c >= 0x01FA && c <= 0x0217) ||
+ (c >= 0x0250 && c <= 0x02A8) ||
+ (c >= 0x02BB && c <= 0x02C1) ||
+ c == 0x0386 ||
+ (c >= 0x0388 && c <= 0x038A) ||
+ c == 0x038C ||
+ (c >= 0x038E && c <= 0x03A1) ||
+ (c >= 0x03A3 && c <= 0x03CE) ||
+ (c >= 0x03D0 && c <= 0x03D6) ||
+ c == 0x03DA ||
+ c == 0x03DC ||
+ c == 0x03DE ||
+ c == 0x03E0 ||
+ (c >= 0x03E2 && c <= 0x03F3) ||
+ (c >= 0x0401 && c <= 0x040C) ||
+ (c >= 0x040E && c <= 0x044F) ||
+ (c >= 0x0451 && c <= 0x045C) ||
+ (c >= 0x045E && c <= 0x0481) ||
+ (c >= 0x0490 && c <= 0x04C4) ||
+ (c >= 0x04C7 && c <= 0x04C8) ||
+ (c >= 0x04CB && c <= 0x04CC) ||
+ (c >= 0x04D0 && c <= 0x04EB) ||
+ (c >= 0x04EE && c <= 0x04F5) ||
+ (c >= 0x04F8 && c <= 0x04F9) ||
+ (c >= 0x0531 && c <= 0x0556) ||
+ c == 0x0559 ||
+ (c >= 0x0561 && c <= 0x0586) ||
+ (c >= 0x05D0 && c <= 0x05EA) ||
+ (c >= 0x05F0 && c <= 0x05F2) ||
+ (c >= 0x0621 && c <= 0x063A) ||
+ (c >= 0x0641 && c <= 0x064A) ||
+ (c >= 0x0671 && c <= 0x06B7) ||
+ (c >= 0x06BA && c <= 0x06BE) ||
+ (c >= 0x06C0 && c <= 0x06CE) ||
+ (c >= 0x06D0 && c <= 0x06D3) ||
+ c == 0x06D5 ||
+ (c >= 0x06E5 && c <= 0x06E6) ||
+ (c >= 0x0905 && c <= 0x0939) ||
+ c == 0x093D ||
+ (c >= 0x0958 && c <= 0x0961) ||
+ (c >= 0x0985 && c <= 0x098C) ||
+ (c >= 0x098F && c <= 0x0990) ||
+ (c >= 0x0993 && c <= 0x09A8) ||
+ (c >= 0x09AA && c <= 0x09B0) ||
+ c == 0x09B2 ||
+ (c >= 0x09B6 && c <= 0x09B9) ||
+ (c >= 0x09DC && c <= 0x09DD) ||
+ (c >= 0x09DF && c <= 0x09E1) ||
+ (c >= 0x09F0 && c <= 0x09F1) ||
+ (c >= 0x0A05 && c <= 0x0A0A) ||
+ (c >= 0x0A0F && c <= 0x0A10) ||
+ (c >= 0x0A13 && c <= 0x0A28) ||
+ (c >= 0x0A2A && c <= 0x0A30) ||
+ (c >= 0x0A32 && c <= 0x0A33) ||
+ (c >= 0x0A35 && c <= 0x0A36) ||
+ (c >= 0x0A38 && c <= 0x0A39) ||
+ (c >= 0x0A59 && c <= 0x0A5C) ||
+ c == 0x0A5E ||
+ (c >= 0x0A72 && c <= 0x0A74) ||
+ (c >= 0x0A85 && c <= 0x0A8B) ||
+ c == 0x0A8D ||
+ (c >= 0x0A8F && c <= 0x0A91) ||
+ (c >= 0x0A93 && c <= 0x0AA8) ||
+ (c >= 0x0AAA && c <= 0x0AB0) ||
+ (c >= 0x0AB2 && c <= 0x0AB3) ||
+ (c >= 0x0AB5 && c <= 0x0AB9) ||
+ c == 0x0ABD ||
+ c == 0x0AE0 ||
+ (c >= 0x0B05 && c <= 0x0B0C) ||
+ (c >= 0x0B0F && c <= 0x0B10) ||
+ (c >= 0x0B13 && c <= 0x0B28) ||
+ (c >= 0x0B2A && c <= 0x0B30) ||
+ (c >= 0x0B32 && c <= 0x0B33) ||
+ (c >= 0x0B36 && c <= 0x0B39) ||
+ c == 0x0B3D ||
+ (c >= 0x0B5C && c <= 0x0B5D) ||
+ (c >= 0x0B5F && c <= 0x0B61) ||
+ (c >= 0x0B85 && c <= 0x0B8A) ||
+ (c >= 0x0B8E && c <= 0x0B90) ||
+ (c >= 0x0B92 && c <= 0x0B95) ||
+ (c >= 0x0B99 && c <= 0x0B9A) ||
+ c == 0x0B9C ||
+ (c >= 0x0B9E && c <= 0x0B9F) ||
+ (c >= 0x0BA3 && c <= 0x0BA4) ||
+ (c >= 0x0BA8 && c <= 0x0BAA) ||
+ (c >= 0x0BAE && c <= 0x0BB5) ||
+ (c >= 0x0BB7 && c <= 0x0BB9) ||
+ (c >= 0x0C05 && c <= 0x0C0C) ||
+ (c >= 0x0C0E && c <= 0x0C10) ||
+ (c >= 0x0C12 && c <= 0x0C28) ||
+ (c >= 0x0C2A && c <= 0x0C33) ||
+ (c >= 0x0C35 && c <= 0x0C39) ||
+ (c >= 0x0C60 && c <= 0x0C61) ||
+ (c >= 0x0C85 && c <= 0x0C8C) ||
+ (c >= 0x0C8E && c <= 0x0C90) ||
+ (c >= 0x0C92 && c <= 0x0CA8) ||
+ (c >= 0x0CAA && c <= 0x0CB3) ||
+ (c >= 0x0CB5 && c <= 0x0CB9) ||
+ c == 0x0CDE ||
+ (c >= 0x0CE0 && c <= 0x0CE1) ||
+ (c >= 0x0D05 && c <= 0x0D0C) ||
+ (c >= 0x0D0E && c <= 0x0D10) ||
+ (c >= 0x0D12 && c <= 0x0D28) ||
+ (c >= 0x0D2A && c <= 0x0D39) ||
+ (c >= 0x0D60 && c <= 0x0D61) ||
+ (c >= 0x0E01 && c <= 0x0E2E) ||
+ c == 0x0E30 ||
+ (c >= 0x0E32 && c <= 0x0E33) ||
+ (c >= 0x0E40 && c <= 0x0E45) ||
+ (c >= 0x0E81 && c <= 0x0E82) ||
+ c == 0x0E84 ||
+ (c >= 0x0E87 && c <= 0x0E88) ||
+ c == 0x0E8A ||
+ c == 0x0E8D ||
+ (c >= 0x0E94 && c <= 0x0E97) ||
+ (c >= 0x0E99 && c <= 0x0E9F) ||
+ (c >= 0x0EA1 && c <= 0x0EA3) ||
+ c == 0x0EA5 ||
+ c == 0x0EA7 ||
+ (c >= 0x0EAA && c <= 0x0EAB) ||
+ (c >= 0x0EAD && c <= 0x0EAE) ||
+ c == 0x0EB0 ||
+ (c >= 0x0EB2 && c <= 0x0EB3) ||
+ c == 0x0EBD ||
+ (c >= 0x0EC0 && c <= 0x0EC4) ||
+ (c >= 0x0F40 && c <= 0x0F47) ||
+ (c >= 0x0F49 && c <= 0x0F69) ||
+ (c >= 0x10A0 && c <= 0x10C5) ||
+ (c >= 0x10D0 && c <= 0x10F6) ||
+ c == 0x1100 ||
+ (c >= 0x1102 && c <= 0x1103) ||
+ (c >= 0x1105 && c <= 0x1107) ||
+ c == 0x1109 ||
+ (c >= 0x110B && c <= 0x110C) ||
+ (c >= 0x110E && c <= 0x1112) ||
+ c == 0x113C ||
+ c == 0x113E ||
+ c == 0x1140 ||
+ c == 0x114C ||
+ c == 0x114E ||
+ c == 0x1150 ||
+ (c >= 0x1154 && c <= 0x1155) ||
+ c == 0x1159 ||
+ (c >= 0x115F && c <= 0x1161) ||
+ c == 0x1163 ||
+ c == 0x1165 ||
+ c == 0x1167 ||
+ c == 0x1169 ||
+ (c >= 0x116D && c <= 0x116E) ||
+ (c >= 0x1172 && c <= 0x1173) ||
+ c == 0x1175 ||
+ c == 0x119E ||
+ c == 0x11A8 ||
+ c == 0x11AB ||
+ (c >= 0x11AE && c <= 0x11AF) ||
+ (c >= 0x11B7 && c <= 0x11B8) ||
+ c == 0x11BA ||
+ (c >= 0x11BC && c <= 0x11C2) ||
+ c == 0x11EB ||
+ c == 0x11F0 ||
+ c == 0x11F9 ||
+ (c >= 0x1E00 && c <= 0x1E9B) ||
+ (c >= 0x1EA0 && c <= 0x1EF9) ||
+ (c >= 0x1F00 && c <= 0x1F15) ||
+ (c >= 0x1F18 && c <= 0x1F1D) ||
+ (c >= 0x1F20 && c <= 0x1F45) ||
+ (c >= 0x1F48 && c <= 0x1F4D) ||
+ (c >= 0x1F50 && c <= 0x1F57) ||
+ c == 0x1F59 ||
+ c == 0x1F5B ||
+ c == 0x1F5D ||
+ (c >= 0x1F5F && c <= 0x1F7D) ||
+ (c >= 0x1F80 && c <= 0x1FB4) ||
+ (c >= 0x1FB6 && c <= 0x1FBC) ||
+ c == 0x1FBE ||
+ (c >= 0x1FC2 && c <= 0x1FC4) ||
+ (c >= 0x1FC6 && c <= 0x1FCC) ||
+ (c >= 0x1FD0 && c <= 0x1FD3) ||
+ (c >= 0x1FD6 && c <= 0x1FDB) ||
+ (c >= 0x1FE0 && c <= 0x1FEC) ||
+ (c >= 0x1FF2 && c <= 0x1FF4) ||
+ (c >= 0x1FF6 && c <= 0x1FFC) ||
+ c == 0x2126 ||
+ (c >= 0x212A && c <= 0x212B) ||
+ c == 0x212E ||
+ (c >= 0x2180 && c <= 0x2182) ||
+ (c >= 0x3041 && c <= 0x3094) ||
+ (c >= 0x30A1 && c <= 0x30FA) ||
+ (c >= 0x3105 && c <= 0x312C) ||
+ (c >= 0xAC00 && c <= 0xD7A3))
+ return true; // BaseChar
+ if ((c >= 0x4e00 && c <= 0x9fa5) ||
+ c == 0x3007 ||
+ (c >= 0x3021 && c <= 0x3029))
+ return true; // Ideographic
+ return false;
+ }
+
+ /**
+ * Indicates whether the specified Unicode character matches the Digit
+ * production.
+ */
+ public static boolean isDigit(int c)
+ {
+ return ((c >= 0x0030 && c <= 0x0039) ||
+ (c >= 0x0660 && c <= 0x0669) ||
+ (c >= 0x06F0 && c <= 0x06F9) ||
+ (c >= 0x0966 && c <= 0x096F) ||
+ (c >= 0x09E6 && c <= 0x09EF) ||
+ (c >= 0x0A66 && c <= 0x0A6F) ||
+ (c >= 0x0AE6 && c <= 0x0AEF) ||
+ (c >= 0x0B66 && c <= 0x0B6F) ||
+ (c >= 0x0BE7 && c <= 0x0BEF) ||
+ (c >= 0x0C66 && c <= 0x0C6F) ||
+ (c >= 0x0CE6 && c <= 0x0CEF) ||
+ (c >= 0x0D66 && c <= 0x0D6F) ||
+ (c >= 0x0E50 && c <= 0x0E59) ||
+ (c >= 0x0ED0 && c <= 0x0ED9) ||
+ (c >= 0x0F20 && c <= 0x0F29));
+ }
+
+ /**
+ * Indicates whether the specified Unicode character matches the
+ * CombiningChar production.
+ */
+ public static boolean isCombiningChar(int c)
+ {
+ return ((c >= 0x0300 && c <= 0x0345) ||
+ (c >= 0x0360 && c <= 0x0361) ||
+ (c >= 0x0483 && c <= 0x0486) ||
+ (c >= 0x0591 && c <= 0x05A1) ||
+ (c >= 0x05A3 && c <= 0x05B9) ||
+ (c >= 0x05BB && c <= 0x05BD) ||
+ c == 0x05BF ||
+ (c >= 0x05C1 && c <= 0x05C2) ||
+ c == 0x05C4 ||
+ (c >= 0x064B && c <= 0x0652) ||
+ c == 0x0670 ||
+ (c >= 0x06D6 && c <= 0x06DC) ||
+ (c >= 0x06DD && c <= 0x06DF) ||
+ (c >= 0x06E0 && c <= 0x06E4) ||
+ (c >= 0x06E7 && c <= 0x06E8) ||
+ (c >= 0x06EA && c <= 0x06ED) ||
+ (c >= 0x0901 && c <= 0x0903) ||
+ c == 0x093C ||
+ (c >= 0x093E && c <= 0x094C) ||
+ c == 0x094D ||
+ (c >= 0x0951 && c <= 0x0954) ||
+ (c >= 0x0962 && c <= 0x0963) ||
+ (c >= 0x0981 && c <= 0x0983) ||
+ c == 0x09BC ||
+ c == 0x09BE ||
+ c == 0x09BF ||
+ (c >= 0x09C0 && c <= 0x09C4) ||
+ (c >= 0x09C7 && c <= 0x09C8) ||
+ (c >= 0x09CB && c <= 0x09CD) ||
+ c == 0x09D7 ||
+ (c >= 0x09E2 && c <= 0x09E3) ||
+ c == 0x0A02 ||
+ c == 0x0A3C ||
+ c == 0x0A3E ||
+ c == 0x0A3F ||
+ (c >= 0x0A40 && c <= 0x0A42) ||
+ (c >= 0x0A47 && c <= 0x0A48) ||
+ (c >= 0x0A4B && c <= 0x0A4D) ||
+ (c >= 0x0A70 && c <= 0x0A71) ||
+ (c >= 0x0A81 && c <= 0x0A83) ||
+ c == 0x0ABC ||
+ (c >= 0x0ABE && c <= 0x0AC5) ||
+ (c >= 0x0AC7 && c <= 0x0AC9) ||
+ (c >= 0x0ACB && c <= 0x0ACD) ||
+ (c >= 0x0B01 && c <= 0x0B03) ||
+ c == 0x0B3C ||
+ (c >= 0x0B3E && c <= 0x0B43) ||
+ (c >= 0x0B47 && c <= 0x0B48) ||
+ (c >= 0x0B4B && c <= 0x0B4D) ||
+ (c >= 0x0B56 && c <= 0x0B57) ||
+ (c >= 0x0B82 && c <= 0x0B83) ||
+ (c >= 0x0BBE && c <= 0x0BC2) ||
+ (c >= 0x0BC6 && c <= 0x0BC8) ||
+ (c >= 0x0BCA && c <= 0x0BCD) ||
+ c == 0x0BD7 ||
+ (c >= 0x0C01 && c <= 0x0C03) ||
+ (c >= 0x0C3E && c <= 0x0C44) ||
+ (c >= 0x0C46 && c <= 0x0C48) ||
+ (c >= 0x0C4A && c <= 0x0C4D) ||
+ (c >= 0x0C55 && c <= 0x0C56) ||
+ (c >= 0x0C82 && c <= 0x0C83) ||
+ (c >= 0x0CBE && c <= 0x0CC4) ||
+ (c >= 0x0CC6 && c <= 0x0CC8) ||
+ (c >= 0x0CCA && c <= 0x0CCD) ||
+ (c >= 0x0CD5 && c <= 0x0CD6) ||
+ (c >= 0x0D02 && c <= 0x0D03) ||
+ (c >= 0x0D3E && c <= 0x0D43) ||
+ (c >= 0x0D46 && c <= 0x0D48) ||
+ (c >= 0x0D4A && c <= 0x0D4D) ||
+ c == 0x0D57 ||
+ c == 0x0E31 ||
+ (c >= 0x0E34 && c <= 0x0E3A) ||
+ (c >= 0x0E47 && c <= 0x0E4E) ||
+ c == 0x0EB1 ||
+ (c >= 0x0EB4 && c <= 0x0EB9) ||
+ (c >= 0x0EBB && c <= 0x0EBC) ||
+ (c >= 0x0EC8 && c <= 0x0ECD) ||
+ (c >= 0x0F18 && c <= 0x0F19) ||
+ c == 0x0F35 ||
+ c == 0x0F37 ||
+ c == 0x0F39 ||
+ c == 0x0F3E ||
+ c == 0x0F3F ||
+ (c >= 0x0F71 && c <= 0x0F84) ||
+ (c >= 0x0F86 && c <= 0x0F8B) ||
+ (c >= 0x0F90 && c <= 0x0F95) ||
+ c == 0x0F97 ||
+ (c >= 0x0F99 && c <= 0x0FAD) ||
+ (c >= 0x0FB1 && c <= 0x0FB7) ||
+ c == 0x0FB9 ||
+ (c >= 0x20D0 && c <= 0x20DC) ||
+ c == 0x20E1 ||
+ (c >= 0x302A && c <= 0x302F) ||
+ c == 0x3099 ||
+ c == 0x309A);
+ }
+
+ /**
+ * Indicates whether the specified Unicode character matches the Extender
+ * production.
+ */
+ public static boolean isExtender(int c)
+ {
+ return (c == 0x00B7 ||
+ c == 0x02D0 ||
+ c == 0x02D1 ||
+ c == 0x0387 ||
+ c == 0x0640 ||
+ c == 0x0E46 ||
+ c == 0x0EC6 ||
+ c == 0x3005 ||
+ (c >= 0x3031 && c <= 0x3035) ||
+ (c >= 0x309D && c <= 0x309E) ||
+ (c >= 0x30FC && c <= 0x30FE));
+ }
+
+ /**
+ * Indicates whether the specified Unicode character matches the Char
+ * production.
+ */
+ public static boolean isChar(int c)
+ {
+ return (c >= 0x20 && c < 0xd800) ||
+ (c >= 0xe00 && c < 0xfffd) || // NB exclude 0xfffd
+ (c >= 0x10000 && c < 0x110000) ||
+ c == 0xa || c == 0x9 || c == 0xd;
+ }
+
+ /**
+ * Interns the specified text or not, depending on the value of
+ * stringInterning.
+ */
+ private String intern(String text)
+ {
+ return stringInterning ? text.intern() : text;
+ }
+
+ /**
+ * Report a parsing error.
+ */
+ private void error(String message)
+ throws XMLStreamException
+ {
+ error(message, null);
+ }
+
+ /**
+ * Report a parsing error.
+ */
+ private void error(String message, Object info)
+ throws XMLStreamException
+ {
+ if (info != null)
+ {
+ if (info instanceof String)
+ message += ": \"" + ((String) info) + "\"";
+ else if (info instanceof Character)
+ message += ": '" + ((Character) info) + "'";
+ }
+ throw new XMLStreamException(message);
+ }
+
+ /**
+ * Perform validation of a start-element event.
+ */
+ private void validateStartElement(String elementName)
+ throws XMLStreamException
+ {
+ if (currentContentModel == null)
+ {
+ // root element
+ // VC: Root Element Type
+ if (!elementName.equals(doctype.rootName))
+ error("root element name must match name in DTD");
+ return;
+ }
+ // VC: Element Valid
+ switch (currentContentModel.type)
+ {
+ case ContentModel.EMPTY:
+ error("child element found in empty element", elementName);
+ break;
+ case ContentModel.ELEMENT:
+ LinkedList ctx = (LinkedList) validationStack.getLast();
+ ctx.add(elementName);
+ break;
+ case ContentModel.MIXED:
+ MixedContentModel mm = (MixedContentModel) currentContentModel;
+ if (!mm.containsName(elementName))
+ error("illegal element for content model", elementName);
+ break;
+ }
+ }
+
+ /**
+ * Perform validation of an end-element event.
+ */
+ private void validateEndElement()
+ throws XMLStreamException
+ {
+ if (currentContentModel == null)
+ {
+ // root element
+ // VC: IDREF
+ if (!idrefs.containsAll(ids))
+ error("IDREF values must match the value of some ID attribute");
+ return;
+ }
+ // VC: Element Valid
+ switch (currentContentModel.type)
+ {
+ case ContentModel.ELEMENT:
+ LinkedList ctx = (LinkedList) validationStack.getLast();
+ ElementContentModel ecm = (ElementContentModel) currentContentModel;
+ validateElementContent(ecm, ctx);
+ break;
+ }
+ }
+
+ /**
+ * Perform validation of character data.
+ */
+ private void validatePCData(String text)
+ throws XMLStreamException
+ {
+ // VC: Element Valid
+ switch (currentContentModel.type)
+ {
+ case ContentModel.EMPTY:
+ error("character data found in empty element", text);
+ break;
+ case ContentModel.ELEMENT:
+ boolean white = true;
+ int len = text.length();
+ for (int i = 0; i < len; i++)
+ {
+ char c = text.charAt(i);
+ if (c != ' ' && c != '\t' && c != '\n' && c != '\r')
+ {
+ white = false;
+ break;
+ }
+ }
+ if (!white)
+ error("character data found in element with element content", text);
+ else if (xmlStandalone == Boolean.TRUE && currentContentModel.external)
+ // VC: Standalone Document Declaration
+ error("whitespace in element content of externally declared " +
+ "element in standalone document");
+ break;
+ }
+ }
+
+ /**
+ * Validates the specified validation context (list of child elements)
+ * against the element content model for the current element.
+ */
+ private void validateElementContent(ElementContentModel model,
+ LinkedList children)
+ throws XMLStreamException
+ {
+ // Use regular expression
+ StringBuffer buf = new StringBuffer();
+ for (Iterator i = children.iterator(); i.hasNext(); )
+ {
+ buf.append((String) i.next());
+ buf.append(' ');
+ }
+ String c = buf.toString();
+ String regex = createRegularExpression(model);
+ if (!c.matches(regex))
+ error("element content "+model.text+" does not match expression "+regex, c);
+ }
+
+ /**
+ * Creates the regular expression used to validate an element content
+ * model.
+ */
+ private String createRegularExpression(ElementContentModel model)
+ {
+ if (model.regex == null)
+ {
+ StringBuffer buf = new StringBuffer();
+ buf.append('(');
+ for (Iterator i = model.contentParticles.iterator(); i.hasNext(); )
+ {
+ ContentParticle cp = (ContentParticle) i.next();
+ if (cp.content instanceof String)
+ {
+ buf.append('(');
+ buf.append((String) cp.content);
+ buf.append(' ');
+ buf.append(')');
+ if (cp.max == -1)
+ {
+ if (cp.min == 0)
+ buf.append('*');
+ else
+ buf.append('+');
+ }
+ else if (cp.min == 0)
+ buf.append('?');
+ }
+ else
+ {
+ ElementContentModel ecm = (ElementContentModel) cp.content;
+ buf.append(createRegularExpression(ecm));
+ }
+ if (model.or && i.hasNext())
+ buf.append('|');
+ }
+ buf.append(')');
+ if (model.max == -1)
+ {
+ if (model.min == 0)
+ buf.append('*');
+ else
+ buf.append('+');
+ }
+ else if (model.min == 0)
+ buf.append('?');
+ model.regex = buf.toString();
+ }
+ return model.regex;
+ }
+
+ /**
+ * Performs validation of a document type declaration event.
+ */
+ void validateDoctype()
+ throws XMLStreamException
+ {
+ for (Iterator i = doctype.entityIterator(); i.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ Object entity = entry.getValue();
+ if (entity instanceof ExternalIds)
+ {
+ ExternalIds ids = (ExternalIds) entity;
+ if (ids.notationName != null)
+ {
+ // VC: Notation Declared
+ ExternalIds notation = doctype.getNotation(ids.notationName);
+ if (notation == null)
+ error("Notation name must match the declared name of a " +
+ "notation", ids.notationName);
+ }
+ }
+ }
+ }
+
+ /**
+ * Simple test harness for reading an XML file.
+ * args[0] is the filename of the XML file
+ * If args[1] is "-x", enable XInclude processing
+ */
+ public static void main(String[] args)
+ throws Exception
+ {
+ boolean xIncludeAware = false;
+ if (args.length > 1 && "-x".equals(args[1]))
+ xIncludeAware = true;
+ XMLParser p = new XMLParser(new java.io.FileInputStream(args[0]),
+ absolutize(null, args[0]),
+ true, // validating
+ true, // namespaceAware
+ true, // coalescing,
+ true, // replaceERefs
+ true, // externalEntities
+ true, // supportDTD
+ true, // baseAware
+ true, // stringInterning
+ null,
+ null);
+ XMLStreamReader reader = p;
+ if (xIncludeAware)
+ reader = new XIncludeFilter(p, args[0], true, true, true);
+ try
+ {
+ int event;
+ //do
+ while (reader.hasNext())
+ {
+ event = reader.next();
+ Location loc = reader.getLocation();
+ System.out.print(loc.getLineNumber()+":"+loc.getColumnNumber()+" ");
+ switch (event)
+ {
+ case XMLStreamConstants.START_DOCUMENT:
+ System.out.println("START_DOCUMENT version="+reader.getVersion()+
+ " encoding="+reader.getEncoding());
+ break;
+ case XMLStreamConstants.END_DOCUMENT:
+ System.out.println("END_DOCUMENT");
+ break;
+ case XMLStreamConstants.START_ELEMENT:
+ System.out.println("START_ELEMENT "+reader.getName());
+ int l = reader.getNamespaceCount();
+ for (int i = 0; i < l; i++)
+ System.out.println("\tnamespace "+reader.getNamespacePrefix(i)+
+ "='"+reader.getNamespaceURI(i)+"'");
+ l = reader.getAttributeCount();
+ for (int i = 0; i < l; i++)
+ System.out.println("\tattribute "+reader.getAttributeQName(i)+
+ "='"+reader.getAttributeValue(i)+"'");
+ break;
+ case XMLStreamConstants.END_ELEMENT:
+ System.out.println("END_ELEMENT "+reader.getName());
+ break;
+ case XMLStreamConstants.CHARACTERS:
+ System.out.println("CHARACTERS '"+encodeText(reader.getText())+"'");
+ break;
+ case XMLStreamConstants.CDATA:
+ System.out.println("CDATA '"+encodeText(reader.getText())+"'");
+ break;
+ case XMLStreamConstants.SPACE:
+ System.out.println("SPACE '"+encodeText(reader.getText())+"'");
+ break;
+ case XMLStreamConstants.DTD:
+ System.out.println("DTD "+reader.getText());
+ break;
+ case XMLStreamConstants.ENTITY_REFERENCE:
+ System.out.println("ENTITY_REFERENCE "+reader.getText());
+ break;
+ case XMLStreamConstants.COMMENT:
+ System.out.println("COMMENT '"+encodeText(reader.getText())+"'");
+ break;
+ case XMLStreamConstants.PROCESSING_INSTRUCTION:
+ System.out.println("PROCESSING_INSTRUCTION "+reader.getPITarget()+
+ " "+reader.getPIData());
+ break;
+ case XMLStreamConstants.START_ENTITY:
+ System.out.println("START_ENTITY "+reader.getText());
+ break;
+ case XMLStreamConstants.END_ENTITY:
+ System.out.println("END_ENTITY "+reader.getText());
+ break;
+ default:
+ System.out.println("Unknown event: "+event);
+ }
+ }
+ }
+ catch (XMLStreamException e)
+ {
+ Location l = reader.getLocation();
+ System.out.println("At line "+l.getLineNumber()+
+ ", column "+l.getColumnNumber()+
+ " of "+l.getLocationURI());
+ throw e;
+ }
+ }
+
+ /**
+ * Escapes control characters in the specified text. For debugging.
+ */
+ private static String encodeText(String text)
+ {
+ StringBuffer b = new StringBuffer();
+ int len = text.length();
+ for (int i = 0; i < len; i++)
+ {
+ char c = text.charAt(i);
+ switch (c)
+ {
+ case '\t':
+ b.append("\\t");
+ break;
+ case '\n':
+ b.append("\\n");
+ break;
+ case '\r':
+ b.append("\\r");
+ break;
+ default:
+ b.append(c);
+ }
+ }
+ return b.toString();
+ }
+
+ /**
+ * An attribute instance.
+ */
+ class Attribute
+ {
+
+ /**
+ * Attribute name.
+ */
+ final String name;
+
+ /**
+ * Attribute type as declared in the DTD, or CDATA otherwise.
+ */
+ final String type;
+
+ /**
+ * Whether the attribute was specified or defaulted.
+ */
+ final boolean specified;
+
+ /**
+ * The attribute value.
+ */
+ final String value;
+
+ /**
+ * The namespace prefix.
+ */
+ final String prefix;
+
+ /**
+ * The namespace local-name.
+ */
+ final String localName;
+
+ Attribute(String name, String type, boolean specified, String value)
+ {
+ this.name = name;
+ this.type = type;
+ this.specified = specified;
+ this.value = value;
+ int ci = name.indexOf(':');
+ if (ci == -1)
+ {
+ prefix = null;
+ localName = intern(name);
+ }
+ else
+ {
+ prefix = intern(name.substring(0, ci));
+ localName = intern(name.substring(ci + 1));
+ }
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other instanceof Attribute)
+ {
+ Attribute a = (Attribute) other;
+ if (namespaceAware)
+ {
+ if (!a.localName.equals(localName))
+ return false;
+ String auri = getNamespaceURI(a.prefix);
+ String uri = getNamespaceURI(prefix);
+ if (uri == null && (auri == null ||
+ (input.xml11 && "".equals(auri))))
+ return true;
+ if (uri != null)
+ {
+ if ("".equals(uri) && input.xml11 && "".equals(auri))
+ return true;
+ return uri.equals(auri);
+ }
+ return false;
+ }
+ else
+ return a.name.equals(name);
+ }
+ return false;
+ }
+
+ }
+
+ /**
+ * Representation of a DTD.
+ */
+ class Doctype
+ {
+
+ /**
+ * Name of the root element.
+ */
+ final String rootName;
+
+ /**
+ * Public ID, if any, of external subset.
+ */
+ final String publicId;
+
+ /**
+ * System ID (URL), if any, of external subset.
+ */
+ final String systemId;
+
+ /**
+ * Map of element names to content models.
+ */
+ private final LinkedHashMap elements = new LinkedHashMap();
+
+ /**
+ * Map of element names to maps of attribute declarations.
+ */
+ private final LinkedHashMap attlists = new LinkedHashMap();
+
+ /**
+ * Map of entity names to entities (String or ExternalIds).
+ */
+ private final LinkedHashMap entities = new LinkedHashMap();
+
+ /**
+ * Map of notation names to ExternalIds.
+ */
+ private final LinkedHashMap notations = new LinkedHashMap();
+
+ /**
+ * Map of anonymous keys to comments.
+ */
+ private final LinkedHashMap comments = new LinkedHashMap();
+
+ /**
+ * Map of anonymous keys to processing instructions (String[2]
+ * containing {target, data}).
+ */
+ private final LinkedHashMap pis = new LinkedHashMap();
+
+ /**
+ * List of keys to all markup entries in the DTD.
+ */
+ private final LinkedList entries = new LinkedList();
+
+ /**
+ * Set of the entities defined in the external subset.
+ */
+ private final HashSet externalEntities = new HashSet();
+
+ /**
+ * Set of the notations defined in the external subset.
+ */
+ private final HashSet externalNotations = new HashSet();
+
+ /**
+ * Counter for making anonymous keys.
+ */
+ private int anon = 1;
+
+ /**
+ * Constructor.
+ */
+ Doctype(String rootName, String publicId, String systemId)
+ {
+ this.rootName = rootName;
+ this.publicId = publicId;
+ this.systemId = systemId;
+ }
+
+ /**
+ * Adds an element declaration.
+ * @param name the element name
+ * @param text the content model text
+ * @param model the parsed content model
+ */
+ void addElementDecl(String name, String text, ContentModel model)
+ {
+ if (elements.containsKey(name))
+ return;
+ model.text = text;
+ model.external = (inputStack.size() != 1);
+ elements.put(name, model);
+ entries.add("E" + name);
+ }
+
+ /**
+ * Adds an attribute declaration.
+ * @param ename the element name
+ * @param aname the attribute name
+ * @param decl the attribute declaration details
+ */
+ void addAttributeDecl(String ename, String aname, AttributeDecl decl)
+ {
+ LinkedHashMap attlist = (LinkedHashMap) attlists.get(ename);
+ if (attlist == null)
+ {
+ attlist = new LinkedHashMap();
+ attlists.put(ename, attlist);
+ }
+ else if (attlist.containsKey(aname))
+ return;
+ attlist.put(aname, decl);
+ String key = "A" + ename;
+ if (!entries.contains(key))
+ entries.add(key);
+ }
+
+ /**
+ * Adds an entity declaration.
+ * @param name the entity name
+ * @param text the entity replacement text
+ * @param inExternalSubset if we are in the exernal subset
+ */
+ void addEntityDecl(String name, String text, boolean inExternalSubset)
+ {
+ if (entities.containsKey(name))
+ return;
+ entities.put(name, text);
+ entries.add("e" + name);
+ if (inExternalSubset)
+ externalEntities.add(name);
+ }
+
+ /**
+ * Adds an entity declaration.
+ * @param name the entity name
+ * @param ids the external IDs
+ * @param inExternalSubset if we are in the exernal subset
+ */
+ void addEntityDecl(String name, ExternalIds ids, boolean inExternalSubset)
+ {
+ if (entities.containsKey(name))
+ return;
+ entities.put(name, ids);
+ entries.add("e" + name);
+ if (inExternalSubset)
+ externalEntities.add(name);
+ }
+
+ /**
+ * Adds a notation declaration.
+ * @param name the notation name
+ * @param ids the external IDs
+ * @param inExternalSubset if we are in the exernal subset
+ */
+ void addNotationDecl(String name, ExternalIds ids, boolean inExternalSubset)
+ {
+ if (notations.containsKey(name))
+ return;
+ notations.put(name, ids);
+ entries.add("n" + name);
+ if (inExternalSubset)
+ externalNotations.add(name);
+ }
+
+ /**
+ * Adds a comment.
+ */
+ void addComment(String text)
+ {
+ String key = Integer.toString(anon++);
+ comments.put(key, text);
+ entries.add("c" + key);
+ }
+
+ /**
+ * Adds a processing instruction.
+ */
+ void addPI(String target, String data)
+ {
+ String key = Integer.toString(anon++);
+ pis.put(key, new String[] {target, data});
+ entries.add("p" + key);
+ }
+
+ /**
+ * Returns the content model for the specified element.
+ * @param name the element name
+ */
+ ContentModel getElementModel(String name)
+ {
+ return (ContentModel) elements.get(name);
+ }
+
+ /**
+ * Returns the attribute definition for the given attribute
+ * @param ename the element name
+ * @param aname the attribute name
+ */
+ AttributeDecl getAttributeDecl(String ename, String aname)
+ {
+ LinkedHashMap attlist = (LinkedHashMap) attlists.get(ename);
+ return (attlist == null) ? null : (AttributeDecl) attlist.get(aname);
+ }
+
+ /**
+ * Indicates whether the specified attribute was declared in the DTD.
+ * @param ename the element name
+ * @param aname the attribute name
+ */
+ boolean isAttributeDeclared(String ename, String aname)
+ {
+ LinkedHashMap attlist = (LinkedHashMap) attlists.get(ename);
+ return (attlist == null) ? false : attlist.containsKey(aname);
+ }
+
+ /**
+ * Returns an iterator over the entries in the attribute list for the
+ * given element.
+ * @param ename the element name
+ */
+ Iterator attlistIterator(String ename)
+ {
+ LinkedHashMap attlist = (LinkedHashMap) attlists.get(ename);
+ return (attlist == null) ? Collections.EMPTY_LIST.iterator() :
+ attlist.entrySet().iterator();
+ }
+
+ /**
+ * Returns the entity (String or ExternalIds) for the given entity name.
+ */
+ Object getEntity(String name)
+ {
+ return entities.get(name);
+ }
+
+ /**
+ * Indicates whether the specified entity was declared in the external
+ * subset.
+ */
+ boolean isEntityExternal(String name)
+ {
+ return externalEntities.contains(name);
+ }
+
+ /**
+ * Returns an iterator over the entity map entries.
+ */
+ Iterator entityIterator()
+ {
+ return entities.entrySet().iterator();
+ }
+
+ /**
+ * Returns the notation IDs for the given notation name.
+ */
+ ExternalIds getNotation(String name)
+ {
+ return (ExternalIds) notations.get(name);
+ }
+
+ /**
+ * Indicates whether the specified notation was declared in the external
+ * subset.
+ */
+ boolean isNotationExternal(String name)
+ {
+ return externalNotations.contains(name);
+ }
+
+ /**
+ * Returns the comment associated with the specified (anonymous) key.
+ */
+ String getComment(String key)
+ {
+ return (String) comments.get(key);
+ }
+
+ /**
+ * Returns the processing instruction associated with the specified
+ * (anonymous) key.
+ */
+ String[] getPI(String key)
+ {
+ return (String[]) pis.get(key);
+ }
+
+ /**
+ * Returns an iterator over the keys of the markup entries in this DTD,
+ * in the order declared.
+ */
+ Iterator entryIterator()
+ {
+ return entries.iterator();
+ }
+
+ }
+
+ /**
+ * Combination of an ExternalID and an optional NDataDecl.
+ */
+ class ExternalIds
+ {
+
+ /**
+ * The public ID.
+ */
+ String publicId;
+
+ /**
+ * The system ID.
+ */
+ String systemId;
+
+ /**
+ * The notation name declared with the NDATA keyword.
+ */
+ String notationName;
+ }
+
+ /**
+ * A content model.
+ */
+ abstract class ContentModel
+ {
+ static final int EMPTY = 0;
+ static final int ANY = 1;
+ static final int ELEMENT = 2;
+ static final int MIXED = 3;
+
+ int min;
+ int max;
+ final int type;
+ String text;
+ boolean external;
+
+ ContentModel(int type)
+ {
+ this.type = type;
+ min = 1;
+ max = 1;
+ }
+
+ }
+
+ /**
+ * The EMPTY content model.
+ */
+ class EmptyContentModel
+ extends ContentModel
+ {
+
+ EmptyContentModel()
+ {
+ super(ContentModel.EMPTY);
+ min = 0;
+ max = 0;
+ }
+
+ }
+
+ /**
+ * The ANY content model.
+ */
+ class AnyContentModel
+ extends ContentModel
+ {
+
+ AnyContentModel()
+ {
+ super(ContentModel.ANY);
+ min = 0;
+ max = -1;
+ }
+
+ }
+
+ /**
+ * An element content model.
+ */
+ class ElementContentModel
+ extends ContentModel
+ {
+
+ LinkedList contentParticles;
+ boolean or;
+ String regex; // regular expression cache
+
+ ElementContentModel()
+ {
+ super(ContentModel.ELEMENT);
+ contentParticles = new LinkedList();
+ }
+
+ void addContentParticle(ContentParticle cp)
+ {
+ contentParticles.add(cp);
+ }
+
+ }
+
+ class ContentParticle
+ {
+
+ int min = 1;
+ int max = 1;
+ Object content; // Name (String) or ElementContentModel
+
+ }
+
+ /**
+ * A mixed content model.
+ */
+ class MixedContentModel
+ extends ContentModel
+ {
+
+ private HashSet names;
+
+ MixedContentModel()
+ {
+ super(ContentModel.MIXED);
+ names = new HashSet();
+ }
+
+ void addName(String name)
+ {
+ names.add(name);
+ }
+
+ boolean containsName(String name)
+ {
+ return names.contains(name);
+ }
+
+ }
+
+ /**
+ * An attribute definition.
+ */
+ class AttributeDecl
+ {
+
+ /**
+ * The attribute type (CDATA, ID, etc).
+ */
+ final String type;
+
+ /**
+ * The default value.
+ */
+ final String value;
+
+ /**
+ * The value type (#FIXED, #IMPLIED, etc).
+ */
+ final int valueType;
+
+ /**
+ * The enumeration text.
+ */
+ final String enumeration;
+
+ /**
+ * The enumeration tokens.
+ */
+ final HashSet values;
+
+ /**
+ * Whether this attribute declaration occurred in the external subset.
+ */
+ final boolean external;
+
+ AttributeDecl(String type, String value,
+ int valueType, String enumeration,
+ HashSet values, boolean external)
+ {
+ this.type = type;
+ this.value = value;
+ this.valueType = valueType;
+ this.enumeration = enumeration;
+ this.values = values;
+ this.external = external;
+ }
+
+ }
+
+ /**
+ * Compatibility interface that can be used to resolve based on a public
+ * ID, not just an URL.
+ */
+ interface XMLResolver2
+ extends XMLResolver
+ {
+
+ InputStream resolve(String publicId, String systemId)
+ throws XMLStreamException;
+
+ }
+
+ /**
+ * An XML input source.
+ */
+ static class Input
+ implements Location
+ {
+
+ int line = 1, markLine;
+ int column, markColumn;
+ int offset, markOffset;
+ final String publicId, systemId, name;
+ final boolean report; // report start- and end-entity
+ final boolean normalize; // normalize CR, etc to LF
+
+ InputStream in;
+ Reader reader;
+ UnicodeReader unicodeReader;
+ boolean initialized;
+ String inputEncoding;
+ boolean xml11;
+
+ Input(InputStream in, Reader reader, String publicId, String systemId,
+ String name, String inputEncoding, boolean report,
+ boolean normalize)
+ {
+ if (inputEncoding == null)
+ inputEncoding = "UTF-8";
+ this.inputEncoding = inputEncoding;
+ this.publicId = publicId;
+ this.systemId = systemId;
+ this.name = name;
+ this.report = report;
+ this.normalize = normalize;
+ if (in != null)
+ {
+ if (reader != null)
+ throw new IllegalStateException("both byte and char streams "+
+ "specified");
+ if (normalize)
+ in = new CRLFInputStream(in);
+ in = new BufferedInputStream(in);
+ this.in = in;
+ }
+ else
+ {
+ this.reader = normalize ? new CRLFReader(reader) : reader;
+ unicodeReader = new UnicodeReader(this.reader);
+ }
+ initialized = false;
+ }
+
+ // -- Location --
+
+ public int getCharacterOffset()
+ {
+ return offset;
+ }
+
+ public int getColumnNumber()
+ {
+ return column;
+ }
+
+ public int getLineNumber()
+ {
+ return line;
+ }
+
+ public String getLocationURI()
+ {
+ return systemId;
+ }
+
+ void init()
+ throws IOException
+ {
+ if (initialized)
+ return;
+ if (in != null)
+ detectEncoding();
+ initialized = true;
+ }
+
+ void mark(int len)
+ throws IOException
+ {
+ //System.out.println(" mark:"+len);
+ markOffset = offset;
+ markLine = line;
+ markColumn = column;
+ if (unicodeReader != null)
+ unicodeReader.mark(len);
+ else
+ in.mark(len);
+ }
+
+ /**
+ * Character read.
+ */
+ int read()
+ throws IOException
+ {
+ offset++;
+ int ret = (unicodeReader != null) ? unicodeReader.read() : in.read();
+ if (normalize &&
+ (ret == 0x0d || (xml11 && (ret == 0x85 || ret == 0x2028))))
+ {
+ // Normalize CR etc to LF
+ ret = 0x0a;
+ }
+ // Locator handling
+ if (ret == 0x0a)
+ {
+ line++;
+ column = 0;
+ }
+ else
+ column++;
+ return ret;
+ }
+
+ /**
+ * Block read.
+ */
+ int read(int[] b, int off, int len)
+ throws IOException
+ {
+ int ret;
+ if (unicodeReader != null)
+ ret = unicodeReader.read(b, off, len);
+ else
+ {
+ byte[] b2 = new byte[len];
+ ret = in.read(b2, 0, len);
+ if (ret != -1)
+ {
+ String s = new String(b2, 0, ret, inputEncoding);
+ int[] c = UnicodeReader.toCodePointArray(s);
+ ret = c.length;
+ System.arraycopy(c, 0, b, off, ret);
+ }
+ }
+ if (ret != -1)
+ {
+ // Locator handling
+ for (int i = 0; i < ret; i++)
+ {
+ int c = b[off + i];
+ if (normalize &&
+ (c == 0x0d || (xml11 && (c == 0x85 || c == 0x2028))))
+ {
+ // Normalize CR etc to LF
+ c = 0x0a;
+ b[off + i] = c;
+ }
+ if (c == 0x0a)
+ {
+ line++;
+ column = 0;
+ }
+ else
+ column++;
+ }
+ }
+ return ret;
+ }
+
+ void reset()
+ throws IOException
+ {
+ if (unicodeReader != null)
+ unicodeReader.reset();
+ else
+ in.reset();
+ offset = markOffset;
+ line = markLine;
+ column = markColumn;
+ }
+
+ // Detection of input encoding
+
+ private static final int[] SIGNATURE_UCS_4_1234 =
+ new int[] { 0x00, 0x00, 0x00, 0x3c };
+ private static final int[] SIGNATURE_UCS_4_4321 =
+ new int[] { 0x3c, 0x00, 0x00, 0x00 };
+ private static final int[] SIGNATURE_UCS_4_2143 =
+ new int[] { 0x00, 0x00, 0x3c, 0x00 };
+ private static final int[] SIGNATURE_UCS_4_3412 =
+ new int[] { 0x00, 0x3c, 0x00, 0x00 };
+ private static final int[] SIGNATURE_UCS_2_12 =
+ new int[] { 0xfe, 0xff };
+ private static final int[] SIGNATURE_UCS_2_21 =
+ new int[] { 0xff, 0xfe };
+ private static final int[] SIGNATURE_UCS_2_12_NOBOM =
+ new int[] { 0x00, 0x3c, 0x00, 0x3f };
+ private static final int[] SIGNATURE_UCS_2_21_NOBOM =
+ new int[] { 0x3c, 0x00, 0x3f, 0x00 };
+ private static final int[] SIGNATURE_UTF_8 =
+ new int[] { 0x3c, 0x3f, 0x78, 0x6d };
+ private static final int[] SIGNATURE_UTF_8_BOM =
+ new int[] { 0xef, 0xbb, 0xbf };
+
+ /**
+ * Detect the input encoding.
+ */
+ private void detectEncoding()
+ throws IOException
+ {
+ int[] signature = new int[4];
+ in.mark(4);
+ for (int i = 0; i < 4; i++)
+ signature[i] = in.read();
+ in.reset();
+
+ // 4-byte encodings
+ if (equals(SIGNATURE_UCS_4_1234, signature))
+ {
+ in.read();
+ in.read();
+ in.read();
+ in.read();
+ setInputEncoding("UTF-32BE");
+ }
+ else if (equals(SIGNATURE_UCS_4_4321, signature))
+ {
+ in.read();
+ in.read();
+ in.read();
+ in.read();
+ setInputEncoding("UTF-32LE");
+ }
+ else if (equals(SIGNATURE_UCS_4_2143, signature) ||
+ equals(SIGNATURE_UCS_4_3412, signature))
+ throw new UnsupportedEncodingException("unsupported UCS-4 byte ordering");
+
+ // 2-byte encodings
+ else if (equals(SIGNATURE_UCS_2_12, signature))
+ {
+ in.read();
+ in.read();
+ setInputEncoding("UTF-16BE");
+ }
+ else if (equals(SIGNATURE_UCS_2_21, signature))
+ {
+ in.read();
+ in.read();
+ setInputEncoding("UTF-16LE");
+ }
+ else if (equals(SIGNATURE_UCS_2_12_NOBOM, signature))
+ {
+ //setInputEncoding("UTF-16BE");
+ throw new UnsupportedEncodingException("no byte-order mark for UCS-2 entity");
+ }
+ else if (equals(SIGNATURE_UCS_2_21_NOBOM, signature))
+ {
+ //setInputEncoding("UTF-16LE");
+ throw new UnsupportedEncodingException("no byte-order mark for UCS-2 entity");
+ }
+ // ASCII-derived encodings
+ else if (equals(SIGNATURE_UTF_8, signature))
+ {
+ // UTF-8 input encoding implied, TextDecl
+ }
+ else if (equals(SIGNATURE_UTF_8_BOM, signature))
+ {
+ in.read();
+ in.read();
+ in.read();
+ setInputEncoding("UTF-8");
+ }
+ }
+
+ private static boolean equals(int[] b1, int[] b2)
+ {
+ for (int i = 0; i < b1.length; i++)
+ {
+ if (b1[i] != b2[i])
+ return false;
+ }
+ return true;
+ }
+
+ void setInputEncoding(String encoding)
+ throws IOException
+ {
+ if (encoding.equals(inputEncoding))
+ return;
+ if ("UTF-16".equalsIgnoreCase(encoding) &&
+ inputEncoding.startsWith("UTF-16"))
+ return;
+ if (reader != null)
+ throw new UnsupportedEncodingException("document is not in its " +
+ "declared encoding " +
+ inputEncoding +
+ ": " + encoding);
+ inputEncoding = encoding;
+ finalizeEncoding();
+ }
+
+ void finalizeEncoding()
+ throws IOException
+ {
+ if (reader != null)
+ return;
+ reader = new BufferedReader(new InputStreamReader(in, inputEncoding));
+ unicodeReader = new UnicodeReader(reader);
+ mark(1);
+ }
+
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java b/libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java
index d677048cfa1..6157296c6b8 100644
--- a/libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java
+++ b/libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java
@@ -282,6 +282,8 @@ public class XMLStreamWriterImpl
public void writeEndElement()
throws XMLStreamException
{
+ if (elements.isEmpty())
+ throw new IllegalStateException("no matching start element");
try
{
endStartElement();
diff --git a/libjava/classpath/gnu/xml/transform/AttributeNode.java b/libjava/classpath/gnu/xml/transform/AttributeNode.java
index 1e0eb1e961a..bc5bc30c9c1 100644
--- a/libjava/classpath/gnu/xml/transform/AttributeNode.java
+++ b/libjava/classpath/gnu/xml/transform/AttributeNode.java
@@ -1,5 +1,5 @@
/* AttributeNode.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004,2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -75,13 +75,9 @@ final class AttributeNode
namespace.clone(stylesheet),
source);
if (children != null)
- {
- ret.children = children.clone(stylesheet);
- }
+ ret.children = children.clone(stylesheet);
if (next != null)
- {
- ret.next = next.clone(stylesheet);
- }
+ ret.next = next.clone(stylesheet);
return ret;
}
@@ -113,9 +109,7 @@ final class AttributeNode
// Use XPath string-value of fragment
namespaceValue = Expr.stringValue(fragment);
if (namespaceValue.length() == 0)
- {
- namespaceValue = null;
- }
+ namespaceValue = null;
}
String prefix = getPrefix(nameValue);
@@ -124,9 +118,7 @@ final class AttributeNode
if (prefix != null)
{
if (XMLConstants.XML_NS_PREFIX.equals(prefix))
- {
- namespaceValue = XMLConstants.XML_NS_URI;
- }
+ namespaceValue = XMLConstants.XML_NS_URI;
else
{
// Resolve namespace for this prefix
@@ -153,9 +145,7 @@ final class AttributeNode
// Resolve prefix for this namespace
prefix = source.lookupPrefix(namespaceValue);
if (prefix != null)
- {
- nameValue = prefix + ":" + nameValue;
- }
+ nameValue = prefix + ":" + nameValue;
else
{
if (namespaceValue != null)
@@ -196,27 +186,19 @@ final class AttributeNode
if (attrs != null)
{
if (namespace != null)
- {
- attrs.setNamedItemNS(attr);
- }
+ attrs.setNamedItemNS(attr);
else
- {
- attrs.setNamedItem(attr);
- }
+ attrs.setNamedItem(attr);
}
if (children != null)
- {
- children.apply(stylesheet, mode,
- context, pos, len,
- attr, null);
- }
+ children.apply(stylesheet, mode,
+ context, pos, len,
+ attr, null);
}
if (next != null)
- {
- next.apply(stylesheet, mode,
- context, pos, len,
- parent, nextSibling);
- }
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
}
final String getPrefix(String name)
@@ -241,13 +223,9 @@ final class AttributeNode
public boolean references(QName var)
{
if (name != null && name.references(var))
- {
- return true;
- }
+ return true;
if (namespace != null && namespace.references(var))
- {
- return true;
- }
+ return true;
return super.references(var);
}
diff --git a/libjava/classpath/gnu/xml/transform/Bindings.java b/libjava/classpath/gnu/xml/transform/Bindings.java
index c372ea83091..4ee08322317 100644
--- a/libjava/classpath/gnu/xml/transform/Bindings.java
+++ b/libjava/classpath/gnu/xml/transform/Bindings.java
@@ -78,6 +78,11 @@ public class Bindings
*/
final LinkedList withParameters;
+ /**
+ * Only search globals.
+ */
+ boolean global;
+
Bindings(Stylesheet stylesheet)
{
this.stylesheet = stylesheet;
@@ -136,6 +141,12 @@ public class Bindings
public boolean containsKey(QName name, int type)
{
+ if (global)
+ {
+ Map ctx1 = (Map) variables.getLast();
+ Map ctx2 = (Map) parameters.getLast();
+ return (ctx1.containsKey(name) || ctx2.containsKey(name));
+ }
Iterator i = null;
switch (type)
{
@@ -165,6 +176,17 @@ public class Bindings
public Object get(QName name, Node context, int pos, int len)
{
+ if (global)
+ {
+ Map ctx = (Map) variables.getLast();
+ Object ret = ctx.get(name);
+ if (ret == null)
+ {
+ ctx = (Map) parameters.getLast();
+ ret = ctx.get(name);
+ }
+ return ret;
+ }
//System.err.println("bindings.get: "+name);
//System.err.println("\t"+toString());
Object ret = null;
diff --git a/libjava/classpath/gnu/xml/transform/ElementAvailableFunction.java b/libjava/classpath/gnu/xml/transform/ElementAvailableFunction.java
index 84cb6207af9..aa15981695e 100644
--- a/libjava/classpath/gnu/xml/transform/ElementAvailableFunction.java
+++ b/libjava/classpath/gnu/xml/transform/ElementAvailableFunction.java
@@ -144,8 +144,8 @@ class ElementAvailableFunction
{
return elements.contains(localName) ?
Boolean.TRUE : Boolean.FALSE;
- // TODO extension elements
}
+ // TODO extension elements
return Boolean.FALSE;
}
@@ -153,16 +153,12 @@ class ElementAvailableFunction
{
NamespaceContext n = nsctx;
if (context instanceof NamespaceContext)
- {
- n = (NamespaceContext) context;
- }
+ n = (NamespaceContext) context;
ElementAvailableFunction f = new ElementAvailableFunction(n);
int len = args.size();
List args2 = new ArrayList(len);
for (int i = 0; i < len; i++)
- {
- args2.add(((Expr) args.get(i)).clone(context));
- }
+ args2.add(((Expr) args.get(i)).clone(context));
f.setArguments(args2);
return f;
}
@@ -172,12 +168,15 @@ class ElementAvailableFunction
for (Iterator i = args.iterator(); i.hasNext(); )
{
if (((Expr) i.next()).references(var))
- {
- return true;
- }
+ return true;
}
return false;
}
+ public String toString()
+ {
+ return "element-available(" + args.get(0) + ")";
+ }
+
}
diff --git a/libjava/classpath/gnu/xml/transform/ElementNode.java b/libjava/classpath/gnu/xml/transform/ElementNode.java
index d8f7f6db6db..092c56a4b64 100644
--- a/libjava/classpath/gnu/xml/transform/ElementNode.java
+++ b/libjava/classpath/gnu/xml/transform/ElementNode.java
@@ -82,14 +82,10 @@ final class ElementNode
elementExcludeResultPrefixes = new HashSet();
StringTokenizer st = new StringTokenizer(attr.getNodeValue());
while (st.hasMoreTokens())
- {
- elementExcludeResultPrefixes.add(st.nextToken());
- }
+ elementExcludeResultPrefixes.add(st.nextToken());
}
else
- {
- elementExcludeResultPrefixes = Collections.EMPTY_SET;
- }
+ elementExcludeResultPrefixes = Collections.EMPTY_SET;
}
TemplateNode clone(Stylesheet stylesheet)
@@ -99,19 +95,15 @@ final class ElementNode
namespace.clone(stylesheet),
uas, source);
if (children != null)
- {
- ret.children = children.clone(stylesheet);
- }
+ ret.children = children.clone(stylesheet);
if (next != null)
- {
- ret.next = next.clone(stylesheet);
- }
+ ret.next = next.clone(stylesheet);
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
- Node context, int pos, int len,
- Node parent, Node nextSibling)
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
throws TransformerException
{
Document doc = (parent instanceof Document) ? (Document) parent :
@@ -137,96 +129,70 @@ final class ElementNode
// Use XPath string-value of fragment
namespaceValue = Expr.stringValue(fragment);
if (namespaceValue.length() == 0)
- {
- namespaceValue = null;
- }
- }
-
- String prefix = getPrefix(nameValue);
- if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix))
- {
- int ci = nameValue.indexOf(':');
- nameValue = nameValue.substring(ci + 1);
+ namespaceValue = null;
}
else
- {
- // Namespace aliasing
- if (prefix == null)
- {
- prefix = "#default";
- }
- String resultPrefix =
- (String) stylesheet.namespaceAliases.get(prefix);
- if (resultPrefix != null)
- {
- if ("#default".equals(resultPrefix))
- {
- resultPrefix = null;
- }
- namespaceValue = source.lookupNamespaceURI(resultPrefix);
- }
- if (prefix == "#default")
+ {
+ String prefix = getPrefix(nameValue);
+ if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix))
{
- prefix = null;
+ int ci = nameValue.indexOf(':');
+ nameValue = nameValue.substring(ci + 1);
}
- // Look up ordinary namespace for this prefix
- if (namespaceValue == null)
+ else
{
- if (XMLConstants.XML_NS_PREFIX.equals(prefix))
+ // Namespace aliasing
+ if (prefix == null)
+ prefix = "#default";
+ String resultPrefix =
+ (String) stylesheet.namespaceAliases.get(prefix);
+ if (resultPrefix != null)
{
- namespaceValue = XMLConstants.XML_NS_URI;
+ if ("#default".equals(resultPrefix))
+ resultPrefix = null;
+ namespaceValue = source.lookupNamespaceURI(resultPrefix);
}
- else
+ if (prefix == "#default")
+ prefix = null;
+ // Look up ordinary namespace for this prefix
+ if (namespaceValue == null)
{
- // Resolve namespace for this prefix
- namespaceValue = source.lookupNamespaceURI(prefix);
+ if (XMLConstants.XML_NS_PREFIX.equals(prefix))
+ namespaceValue = XMLConstants.XML_NS_URI;
+ else
+ {
+ // Resolve namespace for this prefix
+ namespaceValue = source.lookupNamespaceURI(prefix);
+ }
}
}
- /*if (prefix == null)
- {
- // Resolve prefix for this namespace
- prefix = parent.lookupPrefix(namespaceValue);
- if (prefix != null)
- {
- nameValue = prefix + ":" + nameValue;
- }
- }*/
}
+
// Create element
Element element = (namespaceValue != null) ?
doc.createElementNS(namespaceValue, nameValue) :
- doc.createElement(nameValue);
+ doc.createElement(nameValue);
if (nextSibling != null)
- {
- parent.insertBefore(element, nextSibling);
- }
+ parent.insertBefore(element, nextSibling);
else
- {
- parent.appendChild(element);
- }
+ parent.appendChild(element);
stylesheet.addNamespaceNodes(source, element, doc,
elementExcludeResultPrefixes);
if (uas != null)
{
StringTokenizer st = new StringTokenizer(uas, " ");
while (st.hasMoreTokens())
- {
- addAttributeSet(stylesheet, mode, context, pos, len,
- element, null, st.nextToken());
- }
+ addAttributeSet(stylesheet, mode, context, pos, len,
+ element, null, st.nextToken());
}
if (children != null)
- {
- children.apply(stylesheet, mode,
- context, pos, len,
- element, null);
- }
+ children.apply(stylesheet, mode,
+ context, pos, len,
+ element, null);
if (next != null)
- {
- next.apply(stylesheet, mode,
- context, pos, len,
- parent, nextSibling);
- }
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
}
final String getPrefix(String name)
@@ -240,41 +206,33 @@ final class ElementNode
Node parent, Node nextSibling, String attributeSet)
throws TransformerException
{
+ stylesheet.bindings.global = true;
for (Iterator i = stylesheet.attributeSets.iterator(); i.hasNext(); )
{
AttributeSet as = (AttributeSet) i.next();
if (!as.name.equals(attributeSet))
- {
- continue;
- }
+ continue;
if (as.uas != null)
{
StringTokenizer st = new StringTokenizer(as.uas, " ");
while (st.hasMoreTokens())
- {
- addAttributeSet(stylesheet, mode, context, pos, len,
- parent, nextSibling, st.nextToken());
- }
+ addAttributeSet(stylesheet, mode, context, pos, len,
+ parent, nextSibling, st.nextToken());
}
if (as.children != null)
- {
- as.children.apply(stylesheet, mode,
- context, pos, len,
- parent, nextSibling);
- }
+ as.children.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
}
+ stylesheet.bindings.global = false;
}
public boolean references(QName var)
{
if (name != null && name.references(var))
- {
- return true;
- }
+ return true;
if (namespace != null && namespace.references(var))
- {
- return true;
- }
+ return true;
return super.references(var);
}
@@ -283,6 +241,11 @@ final class ElementNode
StringBuffer buf = new StringBuffer(getClass().getName());
buf.append('[');
buf.append("name=");
+ if (namespace != null)
+ {
+ buf.append(",namespace=");
+ buf.append(namespace);
+ }
buf.append(name);
if (uas != null)
{
diff --git a/libjava/classpath/gnu/xml/transform/FunctionAvailableFunction.java b/libjava/classpath/gnu/xml/transform/FunctionAvailableFunction.java
index 7daf7ea3f70..ab86401d0e4 100644
--- a/libjava/classpath/gnu/xml/transform/FunctionAvailableFunction.java
+++ b/libjava/classpath/gnu/xml/transform/FunctionAvailableFunction.java
@@ -147,11 +147,16 @@ class FunctionAvailableFunction
uri = nsctx.getNamespaceURI(prefix);
if (uri == null)
{
- return xsltFunctions.contains(localName) ||
- xpathFunctions.contains(localName) ?
+ return (xpathFunctions.contains(localName) ||
+ xsltFunctions.contains(localName)) ?
Boolean.TRUE : Boolean.FALSE;
- // TODO extension functions
}
+ else if (Stylesheet.XSL_NS.equals(uri))
+ {
+ return xsltFunctions.contains(localName) ?
+ Boolean.TRUE : Boolean.FALSE;
+ }
+ // TODO extension functions
return Boolean.FALSE;
}
@@ -159,16 +164,12 @@ class FunctionAvailableFunction
{
NamespaceContext n = nsctx;
if (context instanceof NamespaceContext)
- {
- n = (NamespaceContext) context;
- }
+ n = (NamespaceContext) context;
FunctionAvailableFunction f = new FunctionAvailableFunction(n);
int len = args.size();
List args2 = new ArrayList(len);
for (int i = 0; i < len; i++)
- {
- args2.add(((Expr) args.get(i)).clone(context));
- }
+ args2.add(((Expr) args.get(i)).clone(context));
f.setArguments(args2);
return f;
}
@@ -178,12 +179,15 @@ class FunctionAvailableFunction
for (Iterator i = args.iterator(); i.hasNext(); )
{
if (((Expr) i.next()).references(var))
- {
- return true;
- }
+ return true;
}
return false;
}
+ public String toString()
+ {
+ return "function-available(" + args.get(0) + ")";
+ }
+
}
diff --git a/libjava/classpath/gnu/xml/transform/LiteralNode.java b/libjava/classpath/gnu/xml/transform/LiteralNode.java
index 0be2b35c84d..453c22c5e0d 100644
--- a/libjava/classpath/gnu/xml/transform/LiteralNode.java
+++ b/libjava/classpath/gnu/xml/transform/LiteralNode.java
@@ -1,5 +1,5 @@
/* LiteralNode.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004,2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -77,38 +77,28 @@ final class LiteralNode
elementExcludeResultPrefixes = new HashSet();
StringTokenizer st = new StringTokenizer(attr.getNodeValue());
while (st.hasMoreTokens())
- {
- elementExcludeResultPrefixes.add(st.nextToken());
- }
+ elementExcludeResultPrefixes.add(st.nextToken());
}
else
- {
- elementExcludeResultPrefixes = Collections.EMPTY_SET;
- }
+ elementExcludeResultPrefixes = Collections.EMPTY_SET;
}
else
- {
- elementExcludeResultPrefixes = null;
- }
+ elementExcludeResultPrefixes = null;
}
TemplateNode clone(Stylesheet stylesheet)
{
TemplateNode ret = new LiteralNode(source);
if (children != null)
- {
- ret.children = children.clone(stylesheet);
- }
+ ret.children = children.clone(stylesheet);
if (next != null)
- {
- ret.next = next.clone(stylesheet);
- }
+ ret.next = next.clone(stylesheet);
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
- Node context, int pos, int len,
- Node parent, Node nextSibling)
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
throws TransformerException
{
Node result = null;
@@ -127,17 +117,13 @@ final class LiteralNode
{
String prefix = source.getPrefix();
if (prefix == null)
- {
- prefix = "#default";
- }
+ prefix = "#default";
String resultPrefix =
(String) stylesheet.namespaceAliases.get(prefix);
if (resultPrefix != null)
{
if ("#default".equals(resultPrefix))
- {
- resultPrefix = null;
- }
+ resultPrefix = null;
String uri = source.lookupNamespaceURI(resultPrefix);
String name = source.getNodeName();
// Create a new element node in the result document
@@ -189,33 +175,23 @@ final class LiteralNode
result = result2;
}
if (nextSibling != null)
- {
- parent.insertBefore(result, nextSibling);
- }
+ parent.insertBefore(result, nextSibling);
else
- {
- parent.appendChild(result);
- }
+ parent.appendChild(result);
if (nodeType == Node.ELEMENT_NODE)
- {
- stylesheet.addNamespaceNodes(source, result, doc,
- elementExcludeResultPrefixes);
- }
+ stylesheet.addNamespaceNodes(source, result, doc,
+ elementExcludeResultPrefixes);
// children
if (children != null)
- {
- children.apply(stylesheet, mode,
- context, pos, len,
- result, null);
- }
+ children.apply(stylesheet, mode,
+ context, pos, len,
+ result, null);
}
// next sibling
if (next != null)
- {
- next.apply(stylesheet, mode,
- context, pos, len,
- parent, nextSibling);
- }
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
}
public String toString()
diff --git a/libjava/classpath/gnu/xml/transform/MessageNode.java b/libjava/classpath/gnu/xml/transform/MessageNode.java
index 1df716836e7..e8e07c6da29 100644
--- a/libjava/classpath/gnu/xml/transform/MessageNode.java
+++ b/libjava/classpath/gnu/xml/transform/MessageNode.java
@@ -1,5 +1,5 @@
/* MessageNode.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004,2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -37,6 +37,7 @@ exception statement from your version. */
package gnu.xml.transform;
+import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Document;
@@ -53,6 +54,8 @@ final class MessageNode
extends TemplateNode
{
+ static final Logger logger = Logger.getLogger("gnu.xml.transform");
+
final boolean terminate;
MessageNode(boolean terminate)
@@ -64,13 +67,9 @@ final class MessageNode
{
TemplateNode ret = new MessageNode(terminate);
if (children != null)
- {
- ret.children = children.clone(stylesheet);
- }
+ ret.children = children.clone(stylesheet);
if (next != null)
- {
- ret.next = next.clone(stylesheet);
- }
+ ret.next = next.clone(stylesheet);
return ret;
}
@@ -86,16 +85,12 @@ final class MessageNode
DocumentFragment fragment = doc.createDocumentFragment();
children.apply(stylesheet, mode, context, pos, len, fragment, null);
String message = Expr.stringValue(fragment);
- System.err.println(message);
+ logger.info(message);
if (terminate)
- {
- stylesheet.terminated = true;
- }
+ stylesheet.terminated = true;
}
if (next != null && !terminate)
- {
- next.apply(stylesheet, mode, context, pos, len, parent, nextSibling);
- }
+ next.apply(stylesheet, mode, context, pos, len, parent, nextSibling);
}
}
diff --git a/libjava/classpath/gnu/xml/transform/NamespaceProxy.java b/libjava/classpath/gnu/xml/transform/NamespaceProxy.java
new file mode 100644
index 00000000000..b3c233cd7a5
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/NamespaceProxy.java
@@ -0,0 +1,77 @@
+/* NamespaceProxy.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath 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, or (at your option)
+any later version.
+
+GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.transform;
+
+import java.util.Collections;
+import java.util.Iterator;
+import javax.xml.namespace.NamespaceContext;
+import org.w3c.dom.Node;
+
+/**
+ * A namespace context using a DOM node to resolve the namespace.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class NamespaceProxy
+ implements NamespaceContext
+{
+
+ private final Node node;
+
+ NamespaceProxy(Node node)
+ {
+ this.node = node;
+ }
+
+ public String getNamespaceURI(String prefix)
+ {
+ return (node == null) ? null : node.lookupNamespaceURI(prefix);
+ }
+
+ public String getPrefix(String namespaceURI)
+ {
+ return (node == null) ? null : node.lookupPrefix(namespaceURI);
+ }
+
+ public Iterator getPrefixes(String namespaceURI)
+ {
+ // TODO
+ return Collections.singleton(getPrefix(namespaceURI)).iterator();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/StreamSerializer.java b/libjava/classpath/gnu/xml/transform/StreamSerializer.java
index 74b10057c12..fb8b1a601bc 100644
--- a/libjava/classpath/gnu/xml/transform/StreamSerializer.java
+++ b/libjava/classpath/gnu/xml/transform/StreamSerializer.java
@@ -1,5 +1,5 @@
/* StreamSerializer.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004,2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -49,6 +49,8 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
import java.util.Map;
import javax.xml.XMLConstants;
import org.w3c.dom.Attr;
@@ -149,16 +151,25 @@ public class StreamSerializer
HTML_BOOLEAN_ATTRIBUTES.put("script", set);
}
+ // HTML namespace URIs
+ static final HashSet HTML_URIS = new HashSet();
+ static {
+ HTML_URIS.add("http://www.w3.org/1999/xhtml");
+ }
+
protected final String encoding;
final Charset charset;
final CharsetEncoder encoder;
final int mode;
- final Map namespaces;
+ final LinkedList namespaces;
protected String eol;
Collection cdataSectionElements = Collections.EMPTY_SET;
protected boolean discardDefaultContent;
protected boolean xmlDeclaration = true;
+
+ // has a META element with the encoding been added?
+ private boolean htmlEncoded;
public StreamSerializer()
{
@@ -174,14 +185,12 @@ public class StreamSerializer
{
this.mode = mode;
if (encoding == null)
- {
- encoding = "UTF-8";
- }
+ encoding = (mode == Stylesheet.OUTPUT_HTML) ? "ISO-8859-1" : "UTF-8";
this.encoding = encoding.intern();
charset = Charset.forName(this.encoding);
encoder = charset.newEncoder();
this.eol = (eol != null) ? eol : System.getProperty("line.separator");
- namespaces = new HashMap();
+ namespaces = new LinkedList();
}
void setCdataSectionElements(Collection c)
@@ -212,18 +221,14 @@ public class StreamSerializer
throws IOException
{
if (out == null)
- {
- throw new NullPointerException("no output stream");
- }
+ throw new NullPointerException("no output stream");
+ htmlEncoded = false;
String value, prefix;
Node children;
String uri = node.getNamespaceURI();
- boolean defined = false;
short nt = node.getNodeType();
if (convertToCdata && nt == Node.TEXT_NODE)
- {
- nt = Node.CDATA_SECTION_NODE;
- }
+ nt = Node.CDATA_SECTION_NODE;
switch (nt)
{
case Node.ATTRIBUTE_NODE:
@@ -233,27 +238,28 @@ public class StreamSerializer
(prefix != null && prefix.startsWith("xmlns:")))
{
String nsuri = node.getNodeValue();
- if (isDefined(nsuri))
- {
- break;
- }
+ if (isDefined(nsuri, prefix))
+ break;
String name = node.getLocalName();
if (name == null)
{
+ // Namespace-unaware
name = node.getNodeName();
+ int ci = name.indexOf(':');
+ if (ci != -1)
+ name = name.substring(ci + 1);
}
define(nsuri, name);
}
- else if (uri != null && !isDefined(uri))
+ else if (uri != null && !isDefined(uri, prefix))
{
prefix = define(uri, prefix);
String nsname = (prefix == null) ? "xmlns" : "xmlns:" + prefix;
out.write(SPACE);
out.write(encodeText(nsname));
out.write(EQ);
- String nsvalue = "'" + encode(uri, true, true) + "'";
+ String nsvalue = "\"" + encode(uri, true, true) + "\"";
out.write(nsvalue.getBytes(encoding));
- defined = true;
}
out.write(SPACE);
String a_nodeName = node.getNodeName();
@@ -262,27 +268,26 @@ public class StreamSerializer
if (mode == Stylesheet.OUTPUT_HTML &&
a_nodeName.equals(a_nodeValue) &&
isHTMLBoolean((Attr) node, a_nodeName))
- {
- break;
- }
+ break;
out.write(EQ);
- value = "'" + encode(a_nodeValue, true, true) + "'";
+ value = "\"" + encode(a_nodeValue, true, true) + "\"";
out.write(encodeText(value));
break;
case Node.ELEMENT_NODE:
+ pushNamespaceContext();
value = node.getNodeName();
out.write(BRA);
out.write(encodeText(value));
- if (uri != null && !isDefined(uri))
+ prefix = node.getPrefix();
+ if (uri != null && !isDefined(uri, prefix))
{
- prefix = define(uri, node.getPrefix());
+ prefix = define(uri, prefix);
String nsname = (prefix == null) ? "xmlns" : "xmlns:" + prefix;
out.write(SPACE);
out.write(encodeText(nsname));
out.write(EQ);
- String nsvalue = "'" + encode(uri, true, true) + "'";
+ String nsvalue = "\"" + encode(uri, true, true) + "\"";
out.write(encodeText(nsvalue));
- defined = true;
}
NamedNodeMap attrs = node.getAttributes();
if (attrs != null)
@@ -296,9 +301,7 @@ public class StreamSerializer
// NOOP
}
else
- {
- serialize(attr, out, false);
- }
+ serialize(attr, out, false);
}
}
convertToCdata = cdataSectionElements.contains(value);
@@ -317,27 +320,35 @@ public class StreamSerializer
out.write(encodeText(value));
out.write(KET);
}
+ popNamespaceContext();
break;
case Node.TEXT_NODE:
value = node.getNodeValue();
if (!"yes".equals(node.getUserData("disable-output-escaping")))
- {
- value = encode(value, false, false);
- }
+ value = encode(value, false, false);
out.write(encodeText(value));
break;
case Node.CDATA_SECTION_NODE:
- value = "<![CDATA[" + node.getNodeValue() + "]]>";
- out.write(encodeText(value));
+ value = node.getNodeValue();
+ // Where any instanceof of ]]> occur, split into multiple CDATA
+ // sections
+ int bbk = value.indexOf("]]>");
+ while (bbk != -1)
+ {
+ String head = value.substring(0, bbk + 2);
+ out.write(encodeText("<![CDATA[" + head + "]]>"));
+ value = value.substring(bbk + 2);
+ bbk = value.indexOf("]]>");
+ }
+ // Write final tail value
+ out.write(encodeText("<![CDATA[" + value + "]]>"));
break;
case Node.COMMENT_NODE:
value = "<!--" + node.getNodeValue() + "-->";
out.write(encodeText(value));
Node cp = node.getParentNode();
if (cp != null && cp.getNodeType() == Node.DOCUMENT_NODE)
- {
- out.write(encodeText(eol));
- }
+ out.write(encodeText(eol));
break;
case Node.DOCUMENT_NODE:
case Node.DOCUMENT_FRAGMENT_NODE:
@@ -355,29 +366,23 @@ public class StreamSerializer
(Document) node : null;
String version = (doc != null) ? doc.getXmlVersion() : null;
if (version == null)
- {
- version = (String) node.getUserData("version");
- }
+ version = (String) node.getUserData("version");
if (version == null)
- {
- version = "1.0";
- }
+ version = "1.0";
out.write(BRA);
out.write(0x3f);
- out.write("xml version='".getBytes("US-ASCII"));
+ out.write("xml version=\"".getBytes("US-ASCII"));
out.write(version.getBytes("US-ASCII"));
- out.write(APOS);
+ out.write(0x22);
if (!("UTF-8".equalsIgnoreCase(encoding)))
{
- out.write(" encoding='".getBytes("US-ASCII"));
+ out.write(" encoding=\"".getBytes("US-ASCII"));
out.write(encoding.getBytes("US-ASCII"));
- out.write(APOS);
+ out.write(0x22);
}
if ((doc != null && doc.getXmlStandalone()) ||
"yes".equals(node.getUserData("standalone")))
- {
- out.write(" standalone='yes'".getBytes("US-ASCII"));
- }
+ out.write(" standalone=\"yes\"".getBytes("US-ASCII"));
out.write(0x3f);
out.write(KET);
out.write(encodeText(eol));
@@ -387,12 +392,10 @@ public class StreamSerializer
}
else if (mode == Stylesheet.OUTPUT_HTML)
{
- // Ensure that encoding is accessible
+ // Ensure that encoding is accessible if head element is present
String mediaType = (String) node.getUserData("media-type");
if (mediaType == null)
- {
- mediaType = "text/html";
- }
+ mediaType = "text/html";
String contentType = mediaType + "; charset=" +
((encoding.indexOf(' ') != -1) ?
"\"" + encoding + "\"" :
@@ -403,133 +406,87 @@ public class StreamSerializer
for (Node ctx = node.getFirstChild(); ctx != null;
ctx = ctx.getNextSibling())
{
- if (ctx.getNodeType() == Node.ELEMENT_NODE)
+ if (ctx.getNodeType() == Node.ELEMENT_NODE &&
+ isHTMLElement(ctx, "html"))
{
html = ctx;
break;
}
}
- if (html == null)
- {
- html = doc.createElement("html");
- node.appendChild(html);
- }
- Node head = null;
- for (Node ctx = html.getFirstChild(); ctx != null;
- ctx = ctx.getNextSibling())
+ if (html != null)
{
- if (ctx.getNodeType() == Node.ELEMENT_NODE)
- {
- String name = ctx.getLocalName();
- if (name == null)
- {
- name = ctx.getNodeName();
- }
- if ("head".equalsIgnoreCase(name))
- {
- head = ctx;
- break;
- }
- }
- }
- if (head == null)
- {
- head = doc.createElement("head");
- Node c1 = null;
+ Node head = null;
for (Node ctx = html.getFirstChild(); ctx != null;
ctx = ctx.getNextSibling())
{
- if (ctx.getNodeType() == Node.ELEMENT_NODE)
+ if (isHTMLElement(ctx, "head"))
{
- c1 = ctx;
+ head = ctx;
break;
}
}
- if (c1 != null)
- {
- html.insertBefore(head, c1);
- }
- else
- {
- html.appendChild(head);
- }
- }
- Node meta = null;
- Node metaContent = null;
- for (Node ctx = head.getFirstChild(); ctx != null;
- ctx = ctx.getNextSibling())
- {
- if (ctx.getNodeType() == Node.ELEMENT_NODE)
+ if (head != null)
{
- String name = ctx.getLocalName();
- if (name == null)
- {
- name = ctx.getNodeName();
- }
- if ("meta".equalsIgnoreCase(name))
+ Node meta = null;
+ Node metaContent = null;
+ for (Node ctx = head.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
{
- NamedNodeMap metaAttrs = ctx.getAttributes();
- int len = metaAttrs.getLength();
- String httpEquiv = null;
- Node content = null;
- for (int i = 0; i < len; i++)
+ if (isHTMLElement(ctx, "meta"))
{
- Node attr = metaAttrs.item(i);
- String attrName = attr.getNodeName();
- if ("http-equiv".equalsIgnoreCase(attrName))
+ NamedNodeMap metaAttrs = ctx.getAttributes();
+ int len = metaAttrs.getLength();
+ String httpEquiv = null;
+ Node content = null;
+ for (int i = 0; i < len; i++)
{
- httpEquiv = attr.getNodeValue();
+ Node attr = metaAttrs.item(i);
+ String attrName = attr.getNodeName();
+ if ("http-equiv".equalsIgnoreCase(attrName))
+ httpEquiv = attr.getNodeValue();
+ else if ("content".equalsIgnoreCase(attrName))
+ content = attr;
}
- else if ("content".equalsIgnoreCase(attrName))
+ if ("Content-Type".equalsIgnoreCase(httpEquiv))
{
- content = attr;
+ meta = ctx;
+ metaContent = content;
+ break;
}
}
- if ("Content-Type".equalsIgnoreCase(httpEquiv))
- {
- meta = ctx;
- metaContent = content;
- break;
- }
}
+ if (meta == null)
+ {
+ meta = doc.createElement("meta");
+ // Insert first
+ Node first = head.getFirstChild();
+ if (first == null)
+ head.appendChild(meta);
+ else
+ head.insertBefore(meta, first);
+ Node metaHttpEquiv = doc.createAttribute("http-equiv");
+ meta.getAttributes().setNamedItem(metaHttpEquiv);
+ metaHttpEquiv.setNodeValue("Content-Type");
+ }
+ if (metaContent == null)
+ {
+ metaContent = doc.createAttribute("content");
+ meta.getAttributes().setNamedItem(metaContent);
+ }
+ metaContent.setNodeValue(contentType);
+ htmlEncoded = true;
}
}
- if (meta == null)
- {
- meta = doc.createElement("meta");
- // Insert first
- Node first = head.getFirstChild();
- if (first == null)
- {
- head.appendChild(meta);
- }
- else
- {
- head.insertBefore(meta, first);
- }
- Node metaHttpEquiv = doc.createAttribute("http-equiv");
- meta.getAttributes().setNamedItem(metaHttpEquiv);
- metaHttpEquiv.setNodeValue("Content-Type");
- }
- if (metaContent == null)
- {
- metaContent = doc.createAttribute("content");
- meta.getAttributes().setNamedItem(metaContent);
- }
- metaContent.setNodeValue(contentType);
- // phew
}
children = node.getFirstChild();
if (children != null)
- {
- serialize(children, out, convertToCdata);
- }
+ serialize(children, out, convertToCdata);
break;
case Node.DOCUMENT_TYPE_NODE:
DocumentType doctype = (DocumentType) node;
out.write(BRA);
out.write(BANG);
- out.write(encodeText("DOCTYPE "));
+ out.write(encodeText("DOCTYPE "));
value = doctype.getNodeName();
out.write(encodeText(value));
String publicId = doctype.getPublicId();
@@ -569,41 +526,73 @@ public class StreamSerializer
out.write(encodeText(eol));
}
break;
+ default:
+ System.err.println("Unhandled node type: "+nt);
}
- if (defined)
+ }
+
+ boolean isHTMLElement(Node node, String name)
+ {
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ return false;
+ String localName = node.getLocalName();
+ if (localName == null)
+ localName = node.getNodeName();
+ if (!name.equalsIgnoreCase(localName))
+ return false;
+ String uri = node.getNamespaceURI();
+ return (uri == null || HTML_URIS.contains(uri));
+ }
+
+ boolean isDefined(String uri, String prefix)
+ {
+ if (XMLConstants.XML_NS_URI.equals(uri))
+ return "xml".equals(prefix);
+ if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri))
+ return "xmlns".equals(prefix);
+ if (prefix == null)
+ prefix = "";
+ for (Iterator i = namespaces.iterator(); i.hasNext(); )
{
- undefine(uri);
+ Map ctx = (Map) i.next();
+ String val = (String) ctx.get(uri);
+ if (val != null && val.equals(prefix))
+ return true;
}
+ return false;
}
- boolean isDefined(String uri)
+ void pushNamespaceContext()
{
- return XMLConstants.XML_NS_URI.equals(uri) ||
- XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri) ||
- namespaces.containsKey(uri);
+ namespaces.addFirst(new HashMap());
}
String define(String uri, String prefix)
{
- while (namespaces.containsValue(prefix))
+ if (namespaces.isEmpty())
+ return prefix;
+ HashMap ctx = (HashMap) namespaces.getFirst();
+ while (ctx.containsValue(prefix))
{
// Fabricate new prefix
prefix = prefix + "_";
}
- namespaces.put(uri, prefix);
+ ctx.put(uri, prefix);
return prefix;
}
- void undefine(String uri)
+ void popNamespaceContext()
{
- namespaces.remove(uri);
+ namespaces.removeFirst();
}
final byte[] encodeText(String text)
throws IOException
{
encoder.reset();
- if (!encoder.canEncode(text))
+ boolean htmlNeedingEncoding =
+ (mode == Stylesheet.OUTPUT_HTML && !htmlEncoded);
+ if (!encoder.canEncode(text) || htmlNeedingEncoding)
{
// Check each character
StringBuffer buf = new StringBuffer();
@@ -611,11 +600,7 @@ public class StreamSerializer
for (int i = 0; i < len; i++)
{
char c = text.charAt(i);
- if (encoder.canEncode(c))
- {
- buf.append(c);
- }
- else
+ if (!encoder.canEncode(c))
{
// Replace with character entity reference
String hex = Integer.toHexString((int) c);
@@ -623,6 +608,20 @@ public class StreamSerializer
buf.append(hex);
buf.append(';');
}
+ else if (htmlNeedingEncoding)
+ {
+ String entityName = getHTMLCharacterEntity(c);
+ if (entityName != null)
+ {
+ buf.append('&');
+ buf.append(entityName);
+ buf.append(';');
+ }
+ else
+ buf.append(c);
+ }
+ else
+ buf.append(c);
}
text = buf.toString();
}
@@ -656,17 +655,13 @@ public class StreamSerializer
if (c == '<')
{
if (buf == null)
- {
- buf = new StringBuffer(text.substring(0, i));
- }
+ buf = new StringBuffer(text.substring(0, i));
buf.append("&lt;");
}
else if (c == '>')
{
if (buf == null)
- {
- buf = new StringBuffer(text.substring(0, i));
- }
+ buf = new StringBuffer(text.substring(0, i));
buf.append("&gt;");
}
else if (c == '&')
@@ -675,25 +670,19 @@ public class StreamSerializer
text.charAt(i + 1) == '{')
{
if (buf != null)
- {
- buf.append(c);
- }
+ buf.append(c);
}
else
{
if (buf == null)
- {
- buf = new StringBuffer(text.substring(0, i));
- }
+ buf = new StringBuffer(text.substring(0, i));
buf.append("&amp;");
}
}
else if (c == '\'' && inAttr)
{
if (buf == null)
- {
- buf = new StringBuffer(text.substring(0, i));
- }
+ buf = new StringBuffer(text.substring(0, i));
if (mode == Stylesheet.OUTPUT_HTML)
// HTML does not define &apos;, use character entity ref
buf.append("&#x27;");
@@ -703,9 +692,7 @@ public class StreamSerializer
else if (c == '"' && inAttr)
{
if (buf == null)
- {
- buf = new StringBuffer(text.substring(0, i));
- }
+ buf = new StringBuffer(text.substring(0, i));
buf.append("&quot;");
}
else if (encodeCtl)
@@ -713,23 +700,17 @@ public class StreamSerializer
if (c < 0x20)
{
if (buf == null)
- {
- buf = new StringBuffer(text.substring(0, i));
- }
+ buf = new StringBuffer(text.substring(0, i));
buf.append('&');
buf.append('#');
buf.append((int) c);
buf.append(';');
}
else if (buf != null)
- {
- buf.append(c);
- }
+ buf.append(c);
}
else if (buf != null)
- {
- buf.append(c);
- }
+ buf.append(c);
}
return (buf == null) ? text : buf.toString();
}
@@ -763,4 +744,109 @@ public class StreamSerializer
return (attributes != null && attributes.contains(attrName));
}
+ static String getHTMLCharacterEntity(char c)
+ {
+ // Hardcode these here to avoid loading the HTML DTD
+ switch (c)
+ {
+ case 160: return "nbsp";
+ case 161: return "iexcl";
+ case 162: return "cent";
+ case 163: return "pound";
+ case 164: return "curren";
+ case 165: return "yen";
+ case 166: return "brvbar";
+ case 167: return "sect";
+ case 168: return "uml";
+ case 169: return "copy";
+ case 170: return "ordf";
+ case 171: return "laquo";
+ case 172: return "not";
+ case 173: return "shy";
+ case 174: return "reg";
+ case 175: return "macr";
+ case 176: return "deg";
+ case 177: return "plusmn";
+ case 178: return "sup2";
+ case 179: return "sup3";
+ case 180: return "acute";
+ case 181: return "micro";
+ case 182: return "para";
+ case 183: return "middot";
+ case 184: return "cedil";
+ case 185: return "sup1";
+ case 186: return "ordm";
+ case 187: return "raquo";
+ case 188: return "frac14";
+ case 189: return "frac12";
+ case 190: return "frac34";
+ case 191: return "iquest";
+ case 192: return "Agrave";
+ case 193: return "Aacute";
+ case 194: return "Acirc";
+ case 195: return "Atilde";
+ case 196: return "Auml";
+ case 197: return "Aring";
+ case 198: return "AElig";
+ case 199: return "Ccedil";
+ case 200: return "Egrave";
+ case 201: return "Eacute";
+ case 202: return "Ecirc";
+ case 203: return "Euml";
+ case 204: return "Igrave";
+ case 205: return "Iacute";
+ case 206: return "Icirc";
+ case 207: return "Iuml";
+ case 208: return "ETH";
+ case 209: return "Ntilde";
+ case 210: return "Ograve";
+ case 211: return "Oacute";
+ case 212: return "Ocirc";
+ case 213: return "Otilde";
+ case 214: return "Ouml";
+ case 215: return "times";
+ case 216: return "Oslash";
+ case 217: return "Ugrave";
+ case 218: return "Uacute";
+ case 219: return "Ucirc";
+ case 220: return "Uuml";
+ case 221: return "Yacute";
+ case 222: return "THORN";
+ case 223: return "szlig";
+ case 224: return "agrave";
+ case 225: return "aacute";
+ case 226: return "acirc";
+ case 227: return "atilde";
+ case 228: return "auml";
+ case 229: return "aring";
+ case 230: return "aelig";
+ case 231: return "ccedil";
+ case 232: return "egrave";
+ case 233: return "eacute";
+ case 234: return "ecirc";
+ case 235: return "euml";
+ case 236: return "igrave";
+ case 237: return "iacute";
+ case 238: return "icirc";
+ case 239: return "iuml";
+ case 240: return "eth";
+ case 241: return "ntilde";
+ case 242: return "ograve";
+ case 243: return "oacute";
+ case 244: return "ocirc";
+ case 245: return "otilde";
+ case 246: return "ouml";
+ case 247: return "divide";
+ case 248: return "oslash";
+ case 249: return "ugrave";
+ case 250: return "uacute";
+ case 251: return "ucirc";
+ case 252: return "uuml";
+ case 253: return "yacute";
+ case 254: return "thorn";
+ case 255: return "yuml";
+ default: return null;
+ }
+ }
+
}
diff --git a/libjava/classpath/gnu/xml/aelfred2/ContentHandler2.java b/libjava/classpath/gnu/xml/transform/StrippingInstruction.java
index 15161383592..c6391b9c521 100644
--- a/libjava/classpath/gnu/xml/aelfred2/ContentHandler2.java
+++ b/libjava/classpath/gnu/xml/transform/StrippingInstruction.java
@@ -1,5 +1,5 @@
-/* ContentHandler2.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+/* StrippingInstruction.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -35,31 +35,39 @@ this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
-package gnu.xml.aelfred2;
+package gnu.xml.transform;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
+import gnu.xml.xpath.NameTest;
/**
- * Extension to the SAX ContentHandler interface to report parsing events
- * and parameters required by DOM Level 3 but not supported by SAX.
+ * An entry in a strip-space or preserve-space list.
*
* @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
*/
-public interface ContentHandler2
- extends ContentHandler
+class StrippingInstruction
{
+ final NameTest element;
+ final int precedence;
+
+ StrippingInstruction(NameTest element, int precedence)
+ {
+ this.element = element;
+ this.precedence = precedence;
+ }
+
/**
- * Reports the XML declaration.
- * @param version the value of the version attribute in the XML
- * declaration
- * @param encoding the encoding specified in the XML declaration, if any
- * @param standalone the standalone attribute from the XML declaration
- * @param inputEncoding the encoding of the XML input
+ * Returns the <i>default priority</i> of the element name test.
+ * @see http://www.w3.org/TR/xslt#dt-default-priority
*/
- void xmlDecl(String version, String encoding, boolean standalone,
- String inputEncoding)
- throws SAXException;
+ float getPriority()
+ {
+ if (element.matchesAny())
+ return -0.5f;
+ else if (element.matchesAnyLocalName())
+ return -0.25f;
+ else
+ return 0.0f;
+ }
}
diff --git a/libjava/classpath/gnu/xml/transform/Stylesheet.java b/libjava/classpath/gnu/xml/transform/Stylesheet.java
index 99431b699d8..51accaa3b9a 100644
--- a/libjava/classpath/gnu/xml/transform/Stylesheet.java
+++ b/libjava/classpath/gnu/xml/transform/Stylesheet.java
@@ -1,5 +1,5 @@
/* Stylesheet.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004,2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -88,6 +88,8 @@ class Stylesheet
{
static final String XSL_NS = "http://www.w3.org/1999/XSL/Transform";
+ private static final NameTest STYLESHEET_PRESERVE_TEXT =
+ new NameTest(new QName(XSL_NS, "text"), false, false);
static final int OUTPUT_XML = 0;
static final int OUTPUT_HTML = 1;
@@ -208,6 +210,7 @@ class Stylesheet
preserveSpace = new LinkedHashSet();
outputCdataSectionElements = new LinkedHashSet();
xpath = (XPathImpl) factory.xpathFactory.newXPath();
+ xpath.setNamespaceContext(this);
if (parent == null)
{
bindings = new Bindings(this);
@@ -218,7 +221,6 @@ class Stylesheet
keys = new LinkedList();
decimalFormats = new LinkedHashMap();
initDefaultDecimalFormat();
- xpath.setNamespaceContext(this);
xpath.setXPathFunctionResolver(this);
}
else
@@ -241,7 +243,6 @@ class Stylesheet
templates = root.templates;
keys = root.keys;
decimalFormats = root.decimalFormats;
- xpath.setNamespaceContext(root);
xpath.setXPathFunctionResolver(root);
}
xpath.setXPathVariableResolver(bindings);
@@ -276,9 +277,7 @@ class Stylesheet
{
Stylesheet stylesheet = this;
while (stylesheet.parent != null)
- {
- stylesheet = stylesheet.parent;
- }
+ stylesheet = stylesheet.parent;
return stylesheet;
}
@@ -408,9 +407,7 @@ class Stylesheet
throws TransformerException
{
if (debug)
- {
- System.err.println("getTemplate: mode="+mode+" context="+context);
- }
+ System.err.println("getTemplate: mode="+mode+" context="+context);
Set candidates = new TreeSet();
for (Iterator j = templates.iterator(); j.hasNext(); )
{
@@ -425,15 +422,11 @@ class Stylesheet
throw new TransformerException(msg);
}
if (!currentTemplate.imports(t))
- {
- isMatch = false;
- }
+ isMatch = false;
}
//System.err.println("\t"+context+" "+t+"="+isMatch);
if (isMatch)
- {
- candidates.add(t);
- }
+ candidates.add(t);
}
//System.err.println("\tcandidates="+candidates);
if (candidates.isEmpty())
@@ -441,9 +434,7 @@ class Stylesheet
// Apply built-in template
// Current template is unchanged
if (debug)
- {
- System.err.println("\tbuiltInTemplate context="+context);
- }
+ System.err.println("\tbuiltInTemplate context="+context);
switch (context.getNodeType())
{
case Node.ELEMENT_NODE:
@@ -453,6 +444,7 @@ class Stylesheet
case Node.COMMENT_NODE:
return builtInNodeTemplate;
case Node.TEXT_NODE:
+ case Node.CDATA_SECTION_NODE:
case Node.ATTRIBUTE_NODE:
return builtInTextTemplate;
default:
@@ -465,9 +457,7 @@ class Stylesheet
// Set current template
currentTemplate = t;
if (debug)
- {
- System.err.println("\ttemplate="+t+" context="+context);
- }
+ System.err.println("\ttemplate="+t+" context="+context);
return t.node;
}
}
@@ -475,25 +465,17 @@ class Stylesheet
TemplateNode getTemplate(QName mode, QName name)
throws TransformerException
{
- //System.err.println("getTemplate: mode="+mode+" name="+name);
Set candidates = new TreeSet();
for (Iterator j = templates.iterator(); j.hasNext(); )
{
Template t = (Template) j.next();
boolean isMatch = t.matches(name);
- //System.err.println("\t"+name+" "+t+"="+isMatch);
if (isMatch)
- {
- candidates.add(t);
- }
+ candidates.add(t);
}
if (candidates.isEmpty())
- {
- return null;
- //throw new TransformerException("template '" + name + "' not found");
- }
+ return null;
Template t = (Template) candidates.iterator().next();
- //System.err.println("\ttemplate="+t+" context="+context);
return t.node;
}
@@ -538,42 +520,30 @@ class Stylesheet
output = node;
String method = getAttribute(attrs, "method");
if ("xml".equals(method) || method == null)
- {
- outputMethod = OUTPUT_XML;
- }
+ outputMethod = OUTPUT_XML;
else if ("html".equals(method))
- {
- outputMethod = OUTPUT_HTML;
- }
+ outputMethod = OUTPUT_HTML;
else if ("text".equals(method))
- {
- outputMethod = OUTPUT_TEXT;
- }
+ outputMethod = OUTPUT_TEXT;
else
{
String msg = "unsupported output method: " + method;
DOMSourceLocator l = new DOMSourceLocator(node);
throw new TransformerConfigurationException(msg, l);
}
- outputPublicId = getAttribute(attrs, "public-id");
- outputSystemId = getAttribute(attrs, "system-id");
+ outputPublicId = getAttribute(attrs, "doctype-public");
+ outputSystemId = getAttribute(attrs, "doctype-system");
outputEncoding = getAttribute(attrs, "encoding");
String indent = getAttribute(attrs, "indent");
if (indent != null)
- {
- outputIndent = "yes".equals(indent);
- }
+ outputIndent = "yes".equals(indent);
outputVersion = getAttribute(attrs, "version");
String omitXmlDecl = getAttribute(attrs, "omit-xml-declaration");
if (omitXmlDecl != null)
- {
- outputOmitXmlDeclaration = "yes".equals(omitXmlDecl);
- }
+ outputOmitXmlDeclaration = "yes".equals(omitXmlDecl);
String standalone = getAttribute(attrs, "standalone");
if (standalone != null)
- {
- outputStandalone = "yes".equals(standalone);
- }
+ outputStandalone = "yes".equals(standalone);
outputMediaType = getAttribute(attrs, "media-type");
String cdataSectionElements =
getAttribute(attrs, "cdata-section-elements");
@@ -581,9 +551,7 @@ class Stylesheet
{
StringTokenizer st = new StringTokenizer(cdataSectionElements, " ");
while (st.hasMoreTokens())
- {
- outputCdataSectionElements.add(st.nextToken());
- }
+ outputCdataSectionElements.add(st.nextToken());
}
}
@@ -728,9 +696,7 @@ class Stylesheet
parse(node.getFirstChild(), false);
}
else if ("template".equals(name))
- {
- templates.add(parseTemplate(node, attrs));
- }
+ templates.add(parseTemplate(node, attrs));
else if ("param".equals(name) ||
"variable".equals(name))
{
@@ -779,9 +745,7 @@ class Stylesheet
factory.newStylesheet(source, precedence + delta, this);
}
else if ("output".equals(name))
- {
- parseOutput(node, attrs);
- }
+ parseOutput(node, attrs);
else if ("preserve-space".equals(name))
{
String elements =
@@ -790,7 +754,9 @@ class Stylesheet
" \t\n\r");
while (st.hasMoreTokens())
{
- preserveSpace.add(parseNameTest(st.nextToken()));
+ NameTest element = parseNameTest(st.nextToken());
+ preserveSpace.add(new StrippingInstruction(element,
+ precedence));
}
}
else if ("strip-space".equals(name))
@@ -801,25 +767,19 @@ class Stylesheet
" \t\n\r");
while (st.hasMoreTokens())
{
- stripSpace.add(parseNameTest(st.nextToken()));
+ NameTest element = parseNameTest(st.nextToken());
+ stripSpace.add(new StrippingInstruction(element,
+ precedence));
}
}
else if ("key".equals(name))
- {
- parseKey(node, attrs);
- }
+ parseKey(node, attrs);
else if ("decimal-format".equals(name))
- {
- parseDecimalFormat(node, attrs);
- }
+ parseDecimalFormat(node, attrs);
else if ("namespace-alias".equals(name))
- {
- parseNamespaceAlias(node, attrs);
- }
+ parseNamespaceAlias(node, attrs);
else if ("attribute-set".equals(name))
- {
- parseAttributeSet(node, attrs);
- }
+ parseAttributeSet(node, attrs);
}
else if (root)
{
@@ -867,12 +827,10 @@ class Stylesheet
final NameTest parseNameTest(String token)
{
if ("*".equals(token))
- {
- return new NameTest(null, true, true);
- }
+ return new NameTest(null, true, true);
else if (token.endsWith(":*"))
{
- QName qName = getQName(token.substring(0, token.length() - 2));
+ QName qName = getQName(token);
return new NameTest(qName, true, false);
}
else
@@ -984,7 +942,13 @@ class Stylesheet
return ret;
}
- boolean isPreserved(Text text)
+ /**
+ * Whitespace stripping.
+ * @param text the text node
+ * @param source true if a source node, false if a stylesheet text node
+ * @see http://www.w3.org/TR/xslt#strip
+ */
+ boolean isPreserved(Text text, boolean source)
throws TransformerConfigurationException
{
// Check characters in text
@@ -996,39 +960,73 @@ class Stylesheet
{
char c = value.charAt(i);
if (c != 0x20 && c != 0x09 && c != 0x0a && c != 0x0d)
- {
- return true;
- }
+ return true;
}
}
// Check parent node
Node ctx = text.getParentNode();
- if (!preserveSpace.isEmpty())
+ if (source)
{
- for (Iterator i = preserveSpace.iterator(); i.hasNext(); )
+ // Source document text node
+ boolean preserve = true;
+ float psPriority = 0.0f, ssPriority = 0.0f;
+ if (!stripSpace.isEmpty())
{
- NameTest preserveTest = (NameTest) i.next();
- if (preserveTest.matches(ctx, 1, 1))
+ // Conflict resolution
+ StrippingInstruction ssi = null, psi = null;
+ for (Iterator i = stripSpace.iterator(); i.hasNext(); )
+ {
+ StrippingInstruction si = (StrippingInstruction) i.next();
+ if (si.element.matches(ctx, 1, 1))
+ {
+ if (ssi != null)
+ {
+ if (si.precedence < ssi.precedence)
+ continue;
+ float p = si.getPriority();
+ if (p < ssPriority)
+ continue;
+ }
+ ssi = si;
+ }
+ }
+ for (Iterator i = preserveSpace.iterator(); i.hasNext(); )
{
- boolean override = false;
- if (!stripSpace.isEmpty())
+ StrippingInstruction si = (StrippingInstruction) i.next();
+ if (si.element.matches(ctx, 1, 1))
{
- for (Iterator j = stripSpace.iterator(); j.hasNext(); )
+ if (psi != null)
{
- NameTest stripTest = (NameTest) j.next();
- if (stripTest.matches(ctx, 1, 1))
- {
- override = true;
- break;
- }
+ if (si.precedence < psi.precedence)
+ continue;
+ float p = si.getPriority();
+ if (p < psPriority)
+ continue;
}
+ psi = si;
}
- if (!override)
+ }
+ if (ssi != null)
+ {
+ if (psi != null)
{
- return true;
+ if (psi.precedence < ssi.precedence)
+ preserve = false;
+ else if (psPriority < ssPriority)
+ preserve = false;
}
+ else
+ preserve = false;
}
}
+ if (preserve)
+ return true;
+ }
+ else
+ {
+ // Stylesheet text node
+ if (STYLESHEET_PRESERVE_TEXT.matches(ctx, 1, 1))
+ return true;
}
// Check whether any ancestor specified xml:space
while (ctx != null)
@@ -1038,24 +1036,14 @@ class Stylesheet
Element element = (Element) ctx;
String xmlSpace = element.getAttribute("xml:space");
if ("default".equals(xmlSpace))
- {
- break;
- }
+ break;
else if ("preserve".equals(xmlSpace))
- {
- return true;
- }
+ return true;
else if (xmlSpace.length() > 0)
{
String msg = "Illegal value for xml:space: " + xmlSpace;
throw new TransformerConfigurationException(msg);
}
- else if ("text".equals(ctx.getLocalName()) &&
- XSL_NS.equals(ctx.getNamespaceURI()))
- {
- // xsl:text implies xml:space='preserve'
- return true;
- }
}
ctx = ctx.getParentNode();
}
@@ -1071,45 +1059,27 @@ class Stylesheet
if ("document".equals(localName) && (arity == 1 || arity == 2))
{
if (current == null)
- {
throw new RuntimeException("current is null");
- }
return new DocumentFunction(getRootStylesheet(), current);
}
else if ("key".equals(localName) && (arity == 2))
- {
- return new KeyFunction(getRootStylesheet());
- }
+ return new KeyFunction(getRootStylesheet());
else if ("format-number".equals(localName) &&
(arity == 2 || arity == 3))
- {
- return new FormatNumberFunction(getRootStylesheet());
- }
+ return new FormatNumberFunction(getRootStylesheet());
else if ("current".equals(localName) && (arity == 0))
- {
- return new CurrentFunction(getRootStylesheet());
- }
+ return new CurrentFunction(getRootStylesheet());
else if ("unparsed-entity-uri".equals(localName) && (arity == 1))
- {
- return new UnparsedEntityUriFunction();
- }
+ return new UnparsedEntityUriFunction();
else if ("generate-id".equals(localName) &&
(arity == 1 || arity == 0))
- {
- return new GenerateIdFunction();
- }
+ return new GenerateIdFunction();
else if ("system-property".equals(localName) && (arity == 1))
- {
- return new SystemPropertyFunction();
- }
+ return new SystemPropertyFunction();
else if ("element-available".equals(localName) && (arity == 1))
- {
- return new ElementAvailableFunction(this);
- }
+ return new ElementAvailableFunction(new NamespaceProxy(current));
else if ("function-available".equals(localName) && (arity == 1))
- {
- return new FunctionAvailableFunction(this);
- }
+ return new FunctionAvailableFunction(new NamespaceProxy(current));
}
return null;
}
@@ -1127,9 +1097,7 @@ class Stylesheet
QName mode = (m == null) ? null : getQName(m);
String s = getAttribute(attrs, "select");
if (s == null)
- {
- s = "child::node()";
- }
+ s = "child::node()";
Node children = node.getFirstChild();
List sortKeys = parseSortKeys(children);
List withParams = parseWithParams(children);
@@ -1411,13 +1379,9 @@ class Stylesheet
if (tnode != null)
{
if (first == null)
- {
- first = tnode;
- }
+ first = tnode;
if (previous != null)
- {
- previous.next = tnode;
- }
+ previous.next = tnode;
previous = tnode;
}
node = next;
@@ -1438,25 +1402,15 @@ class Stylesheet
{
String name = node.getLocalName();
if ("apply-templates".equals(name))
- {
- return parseApplyTemplates(node);
- }
+ return parseApplyTemplates(node);
else if ("call-template".equals(name))
- {
- return parseCallTemplate(node);
- }
+ return parseCallTemplate(node);
else if ("value-of".equals(name))
- {
- return parseValueOf(node);
- }
+ return parseValueOf(node);
else if ("for-each".equals(name))
- {
- return parseForEach(node);
- }
+ return parseForEach(node);
else if ("if".equals(name))
- {
- return parseIf(node);
- }
+ return parseIf(node);
else if ("choose".equals(name))
{
Node children = node.getFirstChild();
@@ -1465,9 +1419,7 @@ class Stylesheet
return ret;
}
else if ("when".equals(name))
- {
- return parseWhen(node);
- }
+ return parseWhen(node);
else if ("otherwise".equals(name))
{
Node children = node.getFirstChild();
@@ -1476,25 +1428,15 @@ class Stylesheet
return ret;
}
else if ("element".equals(name))
- {
- return parseElement(node);
- }
+ return parseElement(node);
else if ("attribute".equals(name))
- {
- return parseAttribute(node);
- }
+ return parseAttribute(node);
else if ("text".equals(name))
- {
- return parseText(node);
- }
+ return parseText(node);
else if ("copy".equals(name))
- {
- return parseCopy(node);
- }
+ return parseCopy(node);
else if ("processing-instruction".equals(name))
- {
- return parseProcessingInstruction(node);
- }
+ return parseProcessingInstruction(node);
else if ("comment".equals(name))
{
Node children = node.getFirstChild();
@@ -1503,9 +1445,7 @@ class Stylesheet
return ret;
}
else if ("number".equals(name))
- {
- return parseNumber(node);
- }
+ return parseNumber(node);
else if ("param".equals(name) ||
"variable".equals(name))
{
@@ -1538,13 +1478,9 @@ class Stylesheet
return ret;
}
else if ("copy-of".equals(name))
- {
- return parseCopyOf(node);
- }
+ return parseCopyOf(node);
else if ("message".equals(name))
- {
- return parseMessage(node);
- }
+ return parseMessage(node);
else if ("apply-imports".equals(name))
{
Node children = node.getFirstChild();
@@ -1562,22 +1498,30 @@ class Stylesheet
String prefix = node.getPrefix();
if (extensionElementPrefixes.contains(prefix))
{
- // Pass over extension elements
+ // Check for xsl:fallback
+ for (Node ctx = node.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ String ctxUri = ctx.getNamespaceURI();
+ if (XSL_NS.equals(ctxUri) &&
+ "fallback".equals(ctx.getLocalName()))
+ {
+ ctx = ctx.getFirstChild();
+ return (ctx == null) ? null : parse(ctx);
+ }
+ }
+ // Otherwise pass over extension element
return null;
}
switch (node.getNodeType())
{
case Node.TEXT_NODE:
+ case Node.CDATA_SECTION_NODE:
// Determine whether to strip whitespace
Text text = (Text) node;
- if (!isPreserved(text))
+ if (!isPreserved(text, false))
{
// Strip
- /*String data = text.getData().trim();
- if (data.length() > 0)
- {
- text.setData(data);
- } // else */
text.getParentNode().removeChild(text);
return null;
}
@@ -1623,9 +1567,7 @@ class Stylesheet
String aname = attr.getNodeName();
if (Stylesheet.XSL_NS.equals(ans) &&
"use-attribute-sets".equals(attr.getLocalName()))
- {
- continue;
- }
+ continue;
String value = attr.getNodeValue();
TemplateNode grandchild =
parseAttributeValueTemplate(value, node);
@@ -1640,8 +1582,9 @@ class Stylesheet
}
String ename = node.getNodeName();
TemplateNode n = parseAttributeValueTemplate(ename, node);
- TemplateNode ns = (namespaceUri == null) ? null :
- parseAttributeValueTemplate(namespaceUri, node);
+ //TemplateNode ns = (namespaceUri == null) ? null :
+ // parseAttributeValueTemplate(namespaceUri, node);
+ TemplateNode ns = null;
ElementNode ret = new ElementNode(n, ns, useAttributeSets,
node);
ret.children = child;
@@ -1676,9 +1619,7 @@ class Stylesheet
NamedNodeMap attrs = node.getAttributes();
String s = getAttribute(attrs, "select");
if (s == null)
- {
- s = ".";
- }
+ s = ".";
Expr select = (Expr) xpath.compile(s);
String l = getAttribute(attrs, "lang");
TemplateNode lang = (l == null) ? null :
@@ -1728,9 +1669,7 @@ class Stylesheet
ret.add(new WithParam(name, expr));
}
else
- {
- ret.add(new WithParam(name, content));
- }
+ ret.add(new WithParam(name, content));
}
node = node.getNextSibling();
}
@@ -1757,27 +1696,19 @@ class Stylesheet
{
String prefix = attr.getLocalName();
if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix))
- {
- prefix = "#default";
- }
+ prefix = "#default";
String ns = attr.getNodeValue();
// Should the namespace be excluded?
if (XSL_NS.equals(ns) ||
extensionElementPrefixes.contains(prefix) ||
elementExcludeResultPrefixes.contains(prefix) ||
excludeResultPrefixes.contains(prefix))
- {
- continue;
- }
+ continue;
// Is the namespace already defined on the target?
if (prefix == "#default")
- {
- prefix = null;
- }
+ prefix = null;
if (target.lookupNamespaceURI(prefix) != null)
- {
- continue;
- }
+ continue;
attr = attr.cloneNode(true);
attr = doc.adoptNode(attr);
target.getAttributes().setNamedItemNS(attr);
@@ -1786,23 +1717,17 @@ class Stylesheet
}
Node parent = source.getParentNode();
if (parent != null)
- {
- addNamespaceNodes(parent, target, doc, elementExcludeResultPrefixes);
- }
+ addNamespaceNodes(parent, target, doc, elementExcludeResultPrefixes);
}
static final String getAttribute(NamedNodeMap attrs, String name)
{
Node attr = attrs.getNamedItem(name);
if (attr == null)
- {
- return null;
- }
+ return null;
String ret = attr.getNodeValue();
if (ret.length() == 0)
- {
- return null;
- }
+ return null;
return ret;
}
diff --git a/libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java b/libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java
index dde2017ff6b..16e3363f8c6 100644
--- a/libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java
+++ b/libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java
@@ -1,5 +1,5 @@
/* TransformerFactoryImpl.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004,2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -37,7 +37,11 @@ exception statement from your version. */
package gnu.xml.transform;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.net.URL;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -73,7 +77,7 @@ public class TransformerFactoryImpl
{
final XPathFactory xpathFactory;
- final XSLURIResolver resolver;
+ final XSLURIResolver resolver;
ErrorListener userListener;
URIResolver userResolver;
@@ -341,5 +345,46 @@ public class TransformerFactoryImpl
{
return userListener;
}
+
+ /**
+ * Syntax: TransformerFactoryImpl [<stylesheet> [<input> [<output>]]]
+ */
+ public static void main(String[] args)
+ throws Exception
+ {
+ InputStream stylesheet = null, in = null;
+ OutputStream out = null;
+ try
+ {
+ if (args.length > 0)
+ {
+ stylesheet = new FileInputStream(args[0]);
+ if (args.length > 1)
+ {
+ in = new FileInputStream(args[1]);
+ if (args.length > 2)
+ out = new FileOutputStream(args[2]);
+ }
+ }
+ if (in == null)
+ in = System.in;
+ if (out == null)
+ out = System.out;
+ TransformerFactory f = new TransformerFactoryImpl();
+ Transformer t = (stylesheet != null) ?
+ f.newTransformer(new StreamSource(stylesheet)) :
+ f.newTransformer();
+ t.transform(new StreamSource(in), new StreamResult(out));
+ }
+ finally
+ {
+ if (stylesheet != null)
+ stylesheet.close();
+ if (in != null && in instanceof FileInputStream)
+ in.close();
+ if (out != null && out instanceof FileOutputStream)
+ out.close();
+ }
+ }
}
diff --git a/libjava/classpath/gnu/xml/transform/TransformerImpl.java b/libjava/classpath/gnu/xml/transform/TransformerImpl.java
index cf404884736..b7ff668843b 100644
--- a/libjava/classpath/gnu/xml/transform/TransformerImpl.java
+++ b/libjava/classpath/gnu/xml/transform/TransformerImpl.java
@@ -1,5 +1,5 @@
/* TransformerImpl.java --
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004,2005,2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -128,8 +128,6 @@ class TransformerImpl
{
// Suppress mutation events
((DomDocument) doc).setBuilding(true);
- // TODO find a better/more generic way of doing this than
- // casting
}
// Get the result tree
Node parent = null, nextSibling = null;
@@ -147,8 +145,6 @@ class TransformerImpl
DomDocument drdoc = (DomDocument) rdoc;
drdoc.setBuilding(true);
drdoc.setCheckWellformedness(false);
- // TODO find a better/more generic way of doing this than
- // casting
}
}
boolean created = false;
@@ -184,9 +180,7 @@ class TransformerImpl
{
// Done transforming, reset document
if (doc instanceof DomDocument)
- {
- ((DomDocument) doc).setBuilding(false);
- }
+ ((DomDocument) doc).setBuilding(false);
throw e;
}
}
@@ -214,17 +208,11 @@ class TransformerImpl
}
Document sourceDoc = context.getOwnerDocument();
if (sourceDoc != resultDoc)
- {
- clone = resultDoc.adoptNode(clone);
- }
+ clone = resultDoc.adoptNode(clone);
if (nextSibling != null)
- {
- parent.insertBefore(clone, nextSibling);
- }
+ parent.insertBefore(clone, nextSibling);
else
- {
- parent.appendChild(clone);
- }
+ parent.appendChild(clone);
}
else
{
@@ -256,15 +244,18 @@ class TransformerImpl
DomDocument resultDoc = (DomDocument) parent;
Node root = resultDoc.getDocumentElement();
// Add doctype if specified
- if ((publicId != null || systemId != null) &&
- root != null)
+ if (publicId != null || systemId != null)
{
- // We must know the name of the root element to
- // create the document type
- resultDoc.appendChild(new DomDoctype(resultDoc,
- root.getNodeName(),
- publicId,
- systemId));
+ if (root != null)
+ {
+ // We must know the name of the root element to
+ // create the document type
+ DocumentType doctype = new DomDoctype(resultDoc,
+ root.getNodeName(),
+ publicId,
+ systemId);
+ resultDoc.insertBefore(doctype, root);
+ }
}
resultDoc.setBuilding(false);
resultDoc.setCheckWellformedness(true);
@@ -279,43 +270,25 @@ class TransformerImpl
(Document) parent :
parent.getOwnerDocument();
DOMImplementation impl = resultDoc.getImplementation();
- DocumentType doctype =
- impl.createDocumentType(resultDoc.getNodeName(),
- publicId,
- systemId);
- // Try to insert doctype before first element
- Node ctx = parent.getFirstChild();
- for (; ctx != null &&
- ctx.getNodeType() != Node.ELEMENT_NODE;
- ctx = ctx.getNextSibling())
+ Node root = resultDoc.getDocumentElement();
+ if (root != null)
{
- }
- if (ctx != null)
- {
- parent.insertBefore(doctype, ctx);
- }
- else
- {
- parent.appendChild(doctype);
+ DocumentType doctype =
+ impl.createDocumentType(root.getNodeName(),
+ publicId,
+ systemId);
+ resultDoc.insertBefore(doctype, root);
}
}
}
if (version != null)
- {
- parent.setUserData("version", version, stylesheet);
- }
+ parent.setUserData("version", version, stylesheet);
if (omitXmlDeclaration)
- {
- parent.setUserData("omit-xml-declaration", "yes", stylesheet);
- }
+ parent.setUserData("omit-xml-declaration", "yes", stylesheet);
if (standalone)
- {
- parent.setUserData("standalone", "yes", stylesheet);
- }
+ parent.setUserData("standalone", "yes", stylesheet);
if (mediaType != null)
- {
- parent.setUserData("media-type", mediaType, stylesheet);
- }
+ parent.setUserData("media-type", mediaType, stylesheet);
if (cdataSectionElements != null)
{
List list = new LinkedList();
@@ -390,13 +363,9 @@ class TransformerImpl
if (ex != null)
{
if (errorListener != null)
- {
- errorListener.error(new TransformerException(ex));
- }
+ errorListener.error(new TransformerException(ex));
else
- {
- ex.printStackTrace(System.err);
- }
+ ex.printStackTrace(System.err);
}
}
else if (outputTarget instanceof SAXResult)
@@ -407,22 +376,16 @@ class TransformerImpl
ContentHandler ch = sr.getHandler();
LexicalHandler lh = sr.getLexicalHandler();
if (lh == null && ch instanceof LexicalHandler)
- {
- lh = (LexicalHandler) ch;
- }
+ lh = (LexicalHandler) ch;
SAXSerializer serializer = new SAXSerializer();
serializer.serialize(parent, ch, lh);
}
catch (SAXException e)
{
if (errorListener != null)
- {
- errorListener.error(new TransformerException(e));
- }
+ errorListener.error(new TransformerException(e));
else
- {
- e.printStackTrace(System.err);
- }
+ e.printStackTrace(System.err);
}
}
}
@@ -430,7 +393,7 @@ class TransformerImpl
/**
* Strip whitespace from the source tree.
*/
- void strip(Node node)
+ boolean strip(Node node)
throws TransformerConfigurationException
{
short nt = node.getNodeType();
@@ -438,44 +401,101 @@ class TransformerImpl
{
// Replace entity reference with its content
Node parent = node.getParentNode();
+ Node nextSibling = node.getNextSibling();
Node child = node.getFirstChild();
- if (child != null)
- {
- strip(child);
- }
while (child != null)
{
Node next = child.getNextSibling();
node.removeChild(child);
- parent.insertBefore(child, node);
+ if (nextSibling != null)
+ parent.insertBefore(child, nextSibling);
+ else
+ parent.appendChild(child);
child = next;
}
- parent.removeChild(node);
+ return true;
}
if (nt == Node.TEXT_NODE || nt == Node.CDATA_SECTION_NODE)
{
- if (!stylesheet.isPreserved((Text) node))
+ // Denormalize text into whitespace and non-whitespace nodes
+ String text = node.getNodeValue();
+ String[] tokens = tokenizeWhitespace(text);
+ if (tokens.length > 1)
{
- node.getParentNode().removeChild(node);
- }
- else
- {
- String text = node.getNodeValue();
- String stripped = text.trim();
- if (!text.equals(stripped))
+ node.setNodeValue(tokens[0]);
+ Node parent = node.getParentNode();
+ Node nextSibling = node.getNextSibling();
+ Document doc = node.getOwnerDocument();
+ for (int i = 1; i < tokens.length; i++)
{
- node.setNodeValue(stripped);
+ Node newChild = (nt == Node.CDATA_SECTION_NODE) ?
+ doc.createCDATASection(tokens[i]) :
+ doc.createTextNode(tokens[i]);
+ if (nextSibling != null)
+ parent.insertBefore(newChild, nextSibling);
+ else
+ parent.appendChild(newChild);
}
}
+ return !stylesheet.isPreserved((Text) node, true);
}
else
{
- for (Node child = node.getFirstChild(); child != null;
- child = child.getNextSibling())
+ Node child = node.getFirstChild();
+ while (child != null)
{
- strip(child);
+ boolean remove = strip(child);
+ Node next = child.getNextSibling();
+ if (remove)
+ node.removeChild(child);
+ child = next;
}
}
+ return false;
+ }
+
+ /**
+ * Tokenize the specified text into contiguous whitespace-only and
+ * non-whitespace chunks.
+ */
+ private static String[] tokenizeWhitespace(String text)
+ {
+ int len = text.length();
+ int start = 0, end = len - 1;
+ // Find index of text start
+ for (int i = 0; i < len; i++)
+ {
+ char c = text.charAt(i);
+ boolean whitespace = (c == ' ' || c == '\n' || c == '\t' || c == '\r');
+ if (whitespace)
+ start++;
+ else
+ break;
+ }
+ if (start == end) // all whitespace
+ return new String[] { text };
+ // Find index of text end
+ for (int i = end; i > start; i--)
+ {
+ char c = text.charAt(i);
+ boolean whitespace = (c == ' ' || c == '\n' || c == '\t' || c == '\r');
+ if (whitespace)
+ end--;
+ else
+ break;
+ }
+ if (start == 0 && end == len - 1) // all non-whitespace
+ return new String[] { text };
+ // whitespace, then text, then whitespace
+ String[] ret = (start > 0 && end < len - 1) ?
+ new String[3] : new String[2];
+ int i = 0;
+ if (start > 0)
+ ret[i++] = text.substring(0, start);
+ ret[i++] = text.substring(start, end + 1);
+ if (end < len - 1)
+ ret[i++] = text.substring(end + 1);
+ return ret;
}
/**
@@ -487,6 +507,7 @@ class TransformerImpl
throws IOException
{
OutputStream out = null;
+ boolean created = false;
try
{
out = sr.getOutputStream();
@@ -494,9 +515,7 @@ class TransformerImpl
{
Writer writer = sr.getWriter();
if (writer != null)
- {
- out = new WriterOutputStream(writer);
- }
+ out = new WriterOutputStream(writer);
}
if (out == null)
{
@@ -523,6 +542,7 @@ class TransformerImpl
URL url = new URL(systemId);
out = new FileOutputStream(url.getPath());
}
+ created = true;
}
out = new BufferedOutputStream(out);
StreamSerializer serializer =
@@ -539,10 +559,8 @@ class TransformerImpl
{
try
{
- if (out != null)
- {
- out.close();
- }
+ if (out != null && created)
+ out.close();
}
catch (IOException e)
{
@@ -564,17 +582,13 @@ class TransformerImpl
public void setParameter(String name, Object value)
{
if (stylesheet != null)
- {
- stylesheet.bindings.set(new QName(null, name), value, Bindings.PARAM);
- }
+ stylesheet.bindings.set(new QName(null, name), value, Bindings.PARAM);
}
public Object getParameter(String name)
{
if (stylesheet != null)
- {
- return stylesheet.bindings.get(new QName(null, name), null, 1, 1);
- }
+ return stylesheet.bindings.get(new QName(null, name), null, 1, 1);
return null;
}
@@ -601,13 +615,9 @@ class TransformerImpl
throws IllegalArgumentException
{
if (oformat == null)
- {
- outputProperties.clear();
- }
+ outputProperties.clear();
else
- {
- outputProperties.putAll(oformat);
- }
+ outputProperties.putAll(oformat);
}
public Properties getOutputProperties()
@@ -689,9 +699,7 @@ class TransformerImpl
StringBuffer buf = new StringBuffer();
buf.append('\n');
for (int i = 0; i < offset + 1; i++)
- {
- buf.append(INDENT_WHITESPACE);
- }
+ buf.append(INDENT_WHITESPACE);
String ws = buf.toString();
for (Iterator i = children.iterator(); i.hasNext(); )
{
@@ -703,9 +711,7 @@ class TransformerImpl
buf.append('\n');
ws = buf.toString();
for (int i = 0; i < offset; i++)
- {
- buf.append(INDENT_WHITESPACE);
- }
+ buf.append(INDENT_WHITESPACE);
node.appendChild(doc.createTextNode(ws));
}
}
@@ -749,9 +755,7 @@ class TransformerImpl
while (ctx != null)
{
if (ctx.hasChildNodes())
- {
- convertCdataSectionElements(doc, ctx, list);
- }
+ convertCdataSectionElements(doc, ctx, list);
ctx = ctx.getNextSibling();
}
}
@@ -761,9 +765,7 @@ class TransformerImpl
String ln1 = qname.getLocalPart();
String ln2 = node.getLocalName();
if (ln2 == null)
- {
- return ln1.equals(node.getNodeName());
- }
+ return ln1.equals(node.getNodeName());
else
{
String uri1 = qname.getNamespaceURI();
diff --git a/libjava/classpath/gnu/xml/transform/ValueOfNode.java b/libjava/classpath/gnu/xml/transform/ValueOfNode.java
index 430598a94b3..24c229ea3b3 100644
--- a/libjava/classpath/gnu/xml/transform/ValueOfNode.java
+++ b/libjava/classpath/gnu/xml/transform/ValueOfNode.java
@@ -1,5 +1,5 @@
/* ValueOfNode.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004,2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -69,26 +69,18 @@ final class ValueOfNode
TemplateNode ret = new ValueOfNode(select.clone(stylesheet),
disableOutputEscaping);
if (children != null)
- {
- ret.children = children.clone(stylesheet);
- }
+ ret.children = children.clone(stylesheet);
if (next != null)
- {
- ret.next = next.clone(stylesheet);
- }
+ ret.next = next.clone(stylesheet);
return ret;
}
void doApply(Stylesheet stylesheet, QName mode,
- Node context, int pos, int len,
- Node parent, Node nextSibling)
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
throws TransformerException
{
Object ret = select.evaluate(context, pos, len);
- /*if (stylesheet.debug)
- {
- System.err.println("value-of: " + select + " -> " + ret);
- }*/
String value;
if (ret instanceof Collection)
{
@@ -100,47 +92,35 @@ final class ValueOfNode
}
value = buf.toString();
}
+ else if (ret == null)
+ value = "";
else
- {
- value = Expr._string(context, ret);
- }
+ value = Expr._string(context, ret);
if (stylesheet.debug)
- {
- System.err.println("value-of: "+context+" "+ select + " -> "+ value);
- }
+ System.err.println("value-of: "+context+" "+ select + " -> "+ value);
if (value != null && value.length() > 0)
{
Document doc = (parent instanceof Document) ?
(Document) parent : parent.getOwnerDocument();
Text textNode = doc.createTextNode(value);
if (disableOutputEscaping)
- {
- textNode.setUserData("disable-output-escaping", "yes", stylesheet);
- }
+ textNode.setUserData("disable-output-escaping", "yes", stylesheet);
if (nextSibling != null)
- {
- parent.insertBefore(textNode, nextSibling);
- }
+ parent.insertBefore(textNode, nextSibling);
else
- {
- parent.appendChild(textNode);
- }
+ parent.appendChild(textNode);
}
// value-of doesn't process children
if (next != null)
- {
- next.apply(stylesheet, mode,
- context, pos, len,
- parent, nextSibling);
- }
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
}
public boolean references(QName var)
{
if (select != null && select.references(var))
- {
- return true;
- }
+ return true;
return super.references(var);
}
@@ -151,9 +131,7 @@ final class ValueOfNode
buf.append("select=");
buf.append(select);
if (disableOutputEscaping)
- {
- buf.append(",disableOutputEscaping");
- }
+ buf.append(",disableOutputEscaping");
buf.append(']');
return buf.toString();
}
diff --git a/libjava/classpath/gnu/xml/xpath/Expr.java b/libjava/classpath/gnu/xml/xpath/Expr.java
index b4b55dcf94e..76fd49eeff5 100644
--- a/libjava/classpath/gnu/xml/xpath/Expr.java
+++ b/libjava/classpath/gnu/xml/xpath/Expr.java
@@ -1,5 +1,5 @@
/* Expr.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004,2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -233,9 +233,11 @@ public abstract class Expr
*/
public static String _local_name(Node context, Collection nodeSet)
{
- Node node = (nodeSet == null || nodeSet.size() == 0) ? context :
- firstNode(nodeSet);
- return node.getLocalName();
+ if (nodeSet == null || nodeSet.isEmpty())
+ return "";
+ Node node = firstNode(nodeSet);
+ String ret = node.getLocalName();
+ return (ret == null) ? "" : ret;
}
/**
@@ -248,9 +250,11 @@ public abstract class Expr
*/
public static String _namespace_uri(Node context, Collection nodeSet)
{
- Node node = (nodeSet == null || nodeSet.size() == 0) ? context :
- firstNode(nodeSet);
- return node.getNamespaceURI();
+ if (nodeSet == null || nodeSet.isEmpty())
+ return "";
+ Node node = firstNode(nodeSet);
+ String ret = node.getNamespaceURI();
+ return (ret == null) ? "" : ret;
}
/**
@@ -271,17 +275,18 @@ public abstract class Expr
*/
public static String _name(Node context, Collection nodeSet)
{
- Node node = (nodeSet == null || nodeSet.size() == 0) ? context :
- firstNode(nodeSet);
+ if (nodeSet == null || nodeSet.isEmpty())
+ return "";
+ Node node = firstNode(nodeSet);
+ String ret = null;
switch (node.getNodeType())
{
case Node.ATTRIBUTE_NODE:
case Node.ELEMENT_NODE:
case Node.PROCESSING_INSTRUCTION_NODE:
- return node.getNodeName();
- default:
- return "";
+ ret = node.getNodeName();
}
+ return (ret == null) ? "" : ret;
}
/**
@@ -371,7 +376,10 @@ public abstract class Expr
}
if (object instanceof Double)
{
- return ((Double) object).doubleValue() != 0.0;
+ Double value = (Double) object;
+ if (value.isNaN())
+ return false;
+ return value.doubleValue() != 0.0;
}
if (object instanceof String)
{
@@ -473,4 +481,15 @@ public abstract class Expr
}
}
+ static int intValue(Object val)
+ {
+ if (val instanceof Double)
+ {
+ Double d = (Double) val;
+ return d.isNaN() ? 0 : d.intValue();
+ }
+ else
+ return (int) Math.ceil(_number(null, val));
+ }
+
}
diff --git a/libjava/classpath/gnu/xml/xpath/LocalNameFunction.java b/libjava/classpath/gnu/xml/xpath/LocalNameFunction.java
index f8ace9cd5f9..84fb6d48288 100644
--- a/libjava/classpath/gnu/xml/xpath/LocalNameFunction.java
+++ b/libjava/classpath/gnu/xml/xpath/LocalNameFunction.java
@@ -1,5 +1,5 @@
/* LocalNameFunction.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004,2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.xml.xpath;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import javax.xml.namespace.QName;
import org.w3c.dom.Node;
@@ -70,7 +71,8 @@ final class LocalNameFunction
public Object evaluate(Node context, int pos, int len)
{
- Object val = (arg == null) ? null : arg.evaluate(context, pos, len);
+ Object val = (arg == null) ? Collections.singleton(context) :
+ arg.evaluate(context, pos, len);
return _local_name(context, (Collection) val);
}
diff --git a/libjava/classpath/gnu/xml/xpath/NameFunction.java b/libjava/classpath/gnu/xml/xpath/NameFunction.java
index dc5e612037a..ea49741fa57 100644
--- a/libjava/classpath/gnu/xml/xpath/NameFunction.java
+++ b/libjava/classpath/gnu/xml/xpath/NameFunction.java
@@ -1,5 +1,5 @@
/* NameFunction.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004,2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.xml.xpath;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import javax.xml.namespace.QName;
import org.w3c.dom.Node;
@@ -78,7 +79,8 @@ final class NameFunction
public Object evaluate(Node context, int pos, int len)
{
- Object val = (arg == null) ? null : arg.evaluate(context, pos, len);
+ Object val = (arg == null) ? Collections.singleton(context) :
+ arg.evaluate(context, pos, len);
return _name(context, (Collection) val);
}
diff --git a/libjava/classpath/gnu/xml/xpath/NameTest.java b/libjava/classpath/gnu/xml/xpath/NameTest.java
index c89ba4dd16b..1710103903d 100644
--- a/libjava/classpath/gnu/xml/xpath/NameTest.java
+++ b/libjava/classpath/gnu/xml/xpath/NameTest.java
@@ -1,5 +1,5 @@
/* NameTest.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004,2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -91,29 +91,32 @@ public final class NameTest
return false;
}
if (any)
- {
- return true;
- }
+ return true;
String uri = qName.getNamespaceURI();
String nodeUri = node.getNamespaceURI();
- String nodeLocalName = node.getLocalName();
- if (nodeLocalName != null && !equal(uri, nodeUri))
- {
- return false;
- }
+ if (!equal(uri, nodeUri))
+ return false;
if (anyLocalName)
- {
- return true;
- }
+ return true;
String localName = qName.getLocalPart();
- if (nodeLocalName != null)
+ String nodeLocalName = getLocalName(node);
+ return (localName.equals(nodeLocalName));
+ }
+
+ static String getLocalName(Node node)
+ {
+ String localName = node.getLocalName();
+ if (localName == null)
{
- nodeLocalName = node.getNodeName();
+ localName = node.getNodeName();
+ int ci = localName.indexOf(':');
+ if (ci != -1)
+ localName = localName.substring(ci + 1);
}
- return (localName.equals(nodeLocalName));
+ return localName;
}
- final boolean equal(String s1, String s2)
+ static boolean equal(String s1, String s2)
{
return (((s1 == null || s1.length() == 0) &&
(s2 == null || s2.length() == 0)) ||
@@ -133,9 +136,7 @@ public final class NameTest
public String toString ()
{
if (any)
- {
- return "*";
- }
+ return "*";
return qName.toString();
}
diff --git a/libjava/classpath/gnu/xml/xpath/NamespaceTest.java b/libjava/classpath/gnu/xml/xpath/NamespaceTest.java
index 6d41166bcb9..d93b76d9de8 100644
--- a/libjava/classpath/gnu/xml/xpath/NamespaceTest.java
+++ b/libjava/classpath/gnu/xml/xpath/NamespaceTest.java
@@ -81,28 +81,22 @@ public final class NamespaceTest
if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri) ||
XMLConstants.XMLNS_ATTRIBUTE.equals(node.getPrefix()) ||
XMLConstants.XMLNS_ATTRIBUTE.equals(node.getNodeName()))
- {
- break;
- }
+ break;
// Fall through
default:
// Only process namespace attributes
return false;
}
if (any)
- {
- return true;
- }
+ return true;
+ String uri = qName.getNamespaceURI();
+ String nodeUri = node.getNamespaceURI();
+ if (!NameTest.equal(uri, nodeUri))
+ return false;
if (anyLocalName)
- {
- return true;
- }
+ return true;
String localName = qName.getLocalPart();
- String nodeLocalName = node.getLocalName();
- if (nodeLocalName == null)
- {
- nodeLocalName = node.getNodeName();
- }
+ String nodeLocalName = NameTest.getLocalName(node);
return (localName.equals(nodeLocalName));
}
@@ -119,9 +113,7 @@ public final class NamespaceTest
public String toString ()
{
if (any)
- {
- return "*";
- }
+ return "*";
return qName.toString();
}
diff --git a/libjava/classpath/gnu/xml/xpath/NamespaceUriFunction.java b/libjava/classpath/gnu/xml/xpath/NamespaceUriFunction.java
index e67ec42065e..3ae46f7ee71 100644
--- a/libjava/classpath/gnu/xml/xpath/NamespaceUriFunction.java
+++ b/libjava/classpath/gnu/xml/xpath/NamespaceUriFunction.java
@@ -1,5 +1,5 @@
/* NamespaceUriFunction.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004,2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.xml.xpath;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import javax.xml.namespace.QName;
import org.w3c.dom.Node;
@@ -70,7 +71,8 @@ final class NamespaceUriFunction
public Object evaluate(Node context, int pos, int len)
{
- Object val = (arg == null) ? null : arg.evaluate(context, pos, len);
+ Object val = (arg == null) ? Collections.singleton(context) :
+ arg.evaluate(context, pos, len);
return _namespace_uri(context, (Collection) val);
}
diff --git a/libjava/classpath/gnu/xml/xpath/NodeTypeTest.java b/libjava/classpath/gnu/xml/xpath/NodeTypeTest.java
index 807374132e5..09e92d0d9a2 100644
--- a/libjava/classpath/gnu/xml/xpath/NodeTypeTest.java
+++ b/libjava/classpath/gnu/xml/xpath/NodeTypeTest.java
@@ -1,5 +1,5 @@
/* NodeTypeTest.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004,2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -39,6 +39,7 @@ package gnu.xml.xpath;
import javax.xml.namespace.QName;
import org.w3c.dom.Node;
+import org.w3c.dom.ProcessingInstruction;
/**
* Tests whether a node is of a given type.
@@ -83,17 +84,20 @@ public final class NodeTypeTest
case Node.TEXT_NODE:
case Node.CDATA_SECTION_NODE:
case Node.COMMENT_NODE:
+ if (type > 0)
+ {
+ if (nodeType != type)
+ return false;
+ }
+ return true;
case Node.PROCESSING_INSTRUCTION_NODE:
if (type > 0)
{
if (nodeType != type)
- {
- return false;
- }
- if (data != null && !data.equals(node.getNodeValue()))
- {
- return false;
- }
+ return false;
+ if (data != null &&
+ !data.equals(((ProcessingInstruction) node).getTarget()))
+ return false;
}
return true;
default:
diff --git a/libjava/classpath/gnu/xml/xpath/Selector.java b/libjava/classpath/gnu/xml/xpath/Selector.java
index 598038064b5..93408e48b23 100644
--- a/libjava/classpath/gnu/xml/xpath/Selector.java
+++ b/libjava/classpath/gnu/xml/xpath/Selector.java
@@ -1,5 +1,5 @@
/* Selector.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004,2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -85,11 +85,13 @@ public final class Selector
public Selector(int axis, List tests)
{
this.axis = axis;
- this.tests = new Test[tests.size()];
- tests.toArray(this.tests);
- if (axis == NAMESPACE &&
- this.tests.length > 0 &&
- this.tests[0] instanceof NameTest)
+ int len = tests.size();
+ this.tests = new Test[(len == 0) ? 1 : len];
+ if (len > 0)
+ tests.toArray(this.tests);
+ else
+ this.tests[0] = new NameTest(null, true, true);
+ if (axis == NAMESPACE && this.tests[0] instanceof NameTest)
{
NameTest nt = (NameTest) this.tests[0];
this.tests[0] = new NamespaceTest(nt.qName, nt.anyLocalName, nt.any);
@@ -111,16 +113,12 @@ public final class Selector
{
case CHILD:
if (nodeType == Node.ATTRIBUTE_NODE)
- {
- return false;
- }
+ return false;
break;
case ATTRIBUTE:
case NAMESPACE:
if (nodeType != Node.ATTRIBUTE_NODE)
- {
- return false;
- }
+ return false;
break;
case DESCENDANT_OR_SELF:
return true;
@@ -132,13 +130,13 @@ public final class Selector
{
int pos = getContextPosition(context);
int len = getContextSize(context);
+ if (len == 0)
+ System.err.println("WARNING: context size is 0");
for (int j = 0; j < tlen && len > 0; j++)
{
Test test = tests[j];
if (!test.matches(context, pos, len))
- {
- return false;
- }
+ return false;
}
}
return true;
@@ -149,9 +147,7 @@ public final class Selector
int pos = 1;
for (ctx = ctx.getPreviousSibling(); ctx != null;
ctx = ctx.getPreviousSibling())
- {
- pos++;
- }
+ pos++;
return pos;
}
@@ -159,15 +155,17 @@ public final class Selector
{
if (ctx.getNodeType() == Node.ATTRIBUTE_NODE)
{
- Node parent = ((Attr) ctx).getOwnerElement();
- return parent.getAttributes().getLength();
- }
- Node parent = ctx.getParentNode();
- if (parent != null)
- {
- return parent.getChildNodes().getLength();
+ Node owner = ((Attr) ctx).getOwnerElement();
+ return owner.getAttributes().getLength();
}
- return 1;
+ int count = 1;
+ Node sib = ctx.getPreviousSibling();
+ for (; sib != null; sib = sib.getPreviousSibling())
+ count++;
+ sib = ctx.getNextSibling();
+ for (; sib != null; sib = sib.getNextSibling())
+ count++;
+ return count;
}
public Object evaluate(Node context, int pos, int len)
@@ -175,7 +173,6 @@ public final class Selector
Set acc = new LinkedHashSet();
addCandidates(context, acc);
List candidates = new ArrayList(acc);
- //Collections.sort(candidates, documentOrderComparator);
List ret = filterCandidates(candidates, false);
return ret;
}
@@ -184,11 +181,8 @@ public final class Selector
{
Set acc = new LinkedHashSet();
for (Iterator i = ns.iterator(); i.hasNext(); )
- {
- addCandidates((Node) i.next(), acc);
- }
+ addCandidates((Node) i.next(), acc);
List candidates = new ArrayList(acc);
- //Collections.sort(candidates, documentOrderComparator);
List ret = filterCandidates(candidates, true);
return ret;
}
@@ -230,17 +224,7 @@ public final class Selector
}
}
if (test.matches(node, i + 1, len))
- {
- successful.add(node);
- }
- /*
- System.err.println("Testing "+node);
- int p = getContextPosition(node);
- int l = getContextSize(node);
- if (test.matches(node, p, l))
- {
- successful.add(node);
- }*/
+ successful.add(node);
}
candidates = successful;
len = candidates.size();
@@ -305,9 +289,7 @@ public final class Selector
{
acc.add(child);
if (recurse)
- {
- addChildNodes(child, acc, recurse);
- }
+ addChildNodes(child, acc, recurse);
child = child.getNextSibling();
}
}
@@ -320,55 +302,62 @@ public final class Selector
{
acc.add(parent);
if (recurse)
- {
- addParentNode(parent, acc, recurse);
- }
+ addParentNode(parent, acc, recurse);
}
}
void addFollowingNodes(Node context, Collection acc, boolean recurse)
{
- Node cur = context.getNextSibling();
+ if (context != null && recurse)
+ addChildNodes(context, acc, true);
+ Node cur = (context.getNodeType() == Node.ATTRIBUTE_NODE) ? null :
+ context.getNextSibling();
while (cur != null)
{
acc.add(cur);
if (recurse)
- {
- addChildNodes(cur, acc, true);
- }
+ addChildNodes(cur, acc, true);
cur = cur.getNextSibling();
}
if (recurse)
{
- context = (context.getNodeType() == Node.ATTRIBUTE_NODE) ?
- ((Attr) context).getOwnerElement() : context.getParentNode();
- if (context != null)
+ while (context != null)
{
- addFollowingNodes(context, acc, recurse);
+ context = (context.getNodeType() == Node.ATTRIBUTE_NODE) ?
+ ((Attr) context).getOwnerElement() : context.getParentNode();
+ if (context != null)
+ {
+ cur = context.getNextSibling();
+ while (cur != null)
+ {
+ acc.add(cur);
+ if (recurse)
+ addChildNodes(cur, acc, true);
+ cur = cur.getNextSibling();
+ }
+ }
}
}
}
void addPrecedingNodes(Node context, Collection acc, boolean recurse)
{
- Node cur = context.getPreviousSibling();
+ Node cur = (context.getNodeType() == Node.ATTRIBUTE_NODE) ? null :
+ context.getPreviousSibling();
while (cur != null)
{
acc.add(cur);
if (recurse)
- {
- addChildNodes(cur, acc, true);
- }
+ addChildNodes(cur, acc, true);
cur = cur.getPreviousSibling();
}
if (recurse)
{
- context = (context.getNodeType() == Node.ATTRIBUTE_NODE) ?
- ((Attr) context).getOwnerElement() : context.getParentNode();
- if (context != null)
- {
- addPrecedingNodes(context, acc, recurse);
- }
+ cur = context;
+ cur = (cur.getNodeType() == Node.ATTRIBUTE_NODE) ?
+ ((Attr) cur).getOwnerElement() : cur.getParentNode();
+ if (cur != null)
+ addPrecedingNodes(cur, acc, recurse);
}
}
@@ -399,9 +388,7 @@ public final class Selector
{
Node attr = attrs.item(i);
if (isNamespaceAttribute(attr))
- {
- acc.add(attr);
- }
+ acc.add(attr);
}
}
}
@@ -419,9 +406,7 @@ public final class Selector
int len = tests.length;
List tests2 = new ArrayList(len);
for (int i = 0; i < len; i++)
- {
- tests2.add(tests[i].clone(context));
- }
+ tests2.add(tests[i].clone(context));
return new Selector(axis, tests2);
}
@@ -430,9 +415,7 @@ public final class Selector
for (int i = 0; i < tests.length; i++)
{
if (tests[i].references(var))
- {
- return true;
- }
+ return true;
}
return false;
}
@@ -451,13 +434,9 @@ public final class Selector
case ATTRIBUTE:
if (tests.length == 0 ||
(tests[0] instanceof NameTest))
- {
- buf.append('@');
- }
+ buf.append('@');
else
- {
- buf.append("attribute::");
- }
+ buf.append("attribute::");
break;
case CHILD:
//buf.append("child::");
@@ -481,9 +460,7 @@ public final class Selector
if (tests.length == 0 ||
(tests[0] instanceof NodeTypeTest &&
((NodeTypeTest) tests[0]).type == 0))
- {
- return "..";
- }
+ return "..";
buf.append("parent::");
break;
case PRECEDING:
@@ -496,22 +473,16 @@ public final class Selector
if (tests.length == 0 ||
(tests[0] instanceof NodeTypeTest &&
((NodeTypeTest) tests[0]).type == 0))
- {
- return ".";
- }
+ return ".";
buf.append("self::");
break;
}
if (tests.length == 0)
- {
- buf.append('*');
- }
+ buf.append("[error]");
else
{
for (int i = 0; i < tests.length; i++)
- {
- buf.append(tests[i]);
- }
+ buf.append(tests[i]);
}
return buf.toString();
}
diff --git a/libjava/classpath/gnu/xml/xpath/SubstringFunction.java b/libjava/classpath/gnu/xml/xpath/SubstringFunction.java
index d65c4facb8a..e926f6c7aeb 100644
--- a/libjava/classpath/gnu/xml/xpath/SubstringFunction.java
+++ b/libjava/classpath/gnu/xml/xpath/SubstringFunction.java
@@ -78,31 +78,20 @@ final class SubstringFunction
Object val1 = arg1.evaluate(context, pos, len);
Object val2 = arg2.evaluate(context, pos, len);
String s = _string(context, val1);
- int p = (val2 instanceof Double) ?
- ((Double) val2).intValue() :
- (int) Math.round(_number(context, val2));
- p--;
+ int p = Expr.intValue(val2) - 1;
if (p < 0)
- {
- p = 0;
- }
+ p = 0;
int l = s.length() - p;
if (l <= 0)
- {
- return "";
- }
+ return "";
if (arg3 != null)
{
Object val3 = arg3.evaluate(context, pos, len);
- int v3 = (val3 instanceof Double) ?
- ((Double) val3).intValue() :
- (int) Math.round(_number(context, val3));
+ int v3 = Expr.intValue(val3);
if (v3 < l)
- {
- l = v3;
- }
+ l = v3;
}
return s.substring(p, p + l);
OpenPOWER on IntegriCloud