upgrading to nanoxml instead of nanoxml-lite

This commit is contained in:
benfry
2008-05-04 23:31:43 +00:00
parent cc4f5af459
commit 0f643ea4ea
15 changed files with 5765 additions and 2729 deletions
+193
View File
@@ -0,0 +1,193 @@
/* CDATAReader.java NanoXML/Java
*
* $Revision: 1.3 $
* $Date: 2002/01/04 21:03:28 $
* $Name: RELEASE_2_2_1 $
*
* This file is part of NanoXML 2 for Java.
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the
* use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
package processing.xml;
import java.io.Reader;
import java.io.IOException;
/**
* This reader reads data from another reader until the end of a CDATA section
* (]]>) has been encountered.
*
* @author Marc De Scheemaecker
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.3 $
*/
class CDATAReader
extends Reader
{
/**
* The encapsulated reader.
*/
private StdXMLReader reader;
/**
* Saved char.
*/
private char savedChar;
/**
* True if the end of the stream has been reached.
*/
private boolean atEndOfData;
/**
* Creates the reader.
*
* @param reader the encapsulated reader
*/
CDATAReader(StdXMLReader reader)
{
this.reader = reader;
this.savedChar = 0;
this.atEndOfData = false;
}
/**
* Cleans up the object when it's destroyed.
*/
protected void finalize()
throws Throwable
{
this.reader = null;
super.finalize();
}
/**
* Reads a block of data.
*
* @param buffer where to put the read data
* @param offset first position in buffer to put the data
* @param size maximum number of chars to read
*
* @return the number of chars read, or -1 if at EOF
*
* @throws java.io.IOException
* if an error occurred reading the data
*/
public int read(char[] buffer,
int offset,
int size)
throws IOException
{
int charsRead = 0;
if (this.atEndOfData) {
return -1;
}
if ((offset + size) > buffer.length) {
size = buffer.length - offset;
}
while (charsRead < size) {
char ch = this.savedChar;
if (ch == 0) {
ch = this.reader.read();
} else {
this.savedChar = 0;
}
if (ch == ']') {
char ch2 = this.reader.read();
if (ch2 == ']') {
char ch3 = this.reader.read();
if (ch3 == '>') {
this.atEndOfData = true;
break;
}
this.savedChar = ch2;
this.reader.unread(ch3);
} else {
this.reader.unread(ch2);
}
}
buffer[charsRead] = ch;
charsRead++;
}
if (charsRead == 0) {
charsRead = -1;
}
return charsRead;
}
/**
* Skips remaining data and closes the stream.
*
* @throws java.io.IOException
* if an error occurred reading the data
*/
public void close()
throws IOException
{
while (! this.atEndOfData) {
char ch = this.savedChar;
if (ch == 0) {
ch = this.reader.read();
} else {
this.savedChar = 0;
}
if (ch == ']') {
char ch2 = this.reader.read();
if (ch2 == ']') {
char ch3 = this.reader.read();
if (ch3 == '>') {
break;
}
this.savedChar = ch2;
this.reader.unread(ch3);
} else {
this.reader.unread(ch2);
}
}
}
this.atEndOfData = true;
}
}
+212
View File
@@ -0,0 +1,212 @@
/* ContentReader.java NanoXML/Java
*
* $Revision: 1.4 $
* $Date: 2002/01/04 21:03:28 $
* $Name: RELEASE_2_2_1 $
*
* This file is part of NanoXML 2 for Java.
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the
* use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
package processing.xml;
import java.io.Reader;
import java.io.IOException;
/**
* This reader reads data from another reader until a new element has
* been encountered.
*
* @author Marc De Scheemaecker
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
*/
class ContentReader
extends Reader
{
/**
* The encapsulated reader.
*/
private StdXMLReader reader;
/**
* Buffer.
*/
private String buffer;
/**
* Pointer into the buffer.
*/
private int bufferIndex;
/**
* The entity resolver.
*/
private XMLEntityResolver resolver;
/**
* Creates the reader.
*
* @param reader the encapsulated reader
* @param resolver the entity resolver
* @param buffer data that has already been read from <code>reader</code>
*/
ContentReader(StdXMLReader reader,
XMLEntityResolver resolver,
String buffer)
{
this.reader = reader;
this.resolver = resolver;
this.buffer = buffer;
this.bufferIndex = 0;
}
/**
* Cleans up the object when it's destroyed.
*/
protected void finalize()
throws Throwable
{
this.reader = null;
this.resolver = null;
this.buffer = null;
super.finalize();
}
/**
* Reads a block of data.
*
* @param outputBuffer where to put the read data
* @param offset first position in buffer to put the data
* @param size maximum number of chars to read
*
* @return the number of chars read, or -1 if at EOF
*
* @throws java.io.IOException
* if an error occurred reading the data
*/
public int read(char[] outputBuffer,
int offset,
int size)
throws IOException
{
try {
int charsRead = 0;
int bufferLength = this.buffer.length();
if ((offset + size) > outputBuffer.length) {
size = outputBuffer.length - offset;
}
while (charsRead < size) {
String str = "";
char ch;
if (this.bufferIndex >= bufferLength) {
str = XMLUtil.read(this.reader, '&');
ch = str.charAt(0);
} else {
ch = this.buffer.charAt(this.bufferIndex);
this.bufferIndex++;
outputBuffer[charsRead] = ch;
charsRead++;
continue; // don't interprete chars in the buffer
}
if (ch == '<') {
this.reader.unread(ch);
break;
}
if ((ch == '&') && (str.length() > 1)) {
if (str.charAt(1) == '#') {
ch = XMLUtil.processCharLiteral(str);
} else {
XMLUtil.processEntity(str, this.reader, this.resolver);
continue;
}
}
outputBuffer[charsRead] = ch;
charsRead++;
}
if (charsRead == 0) {
charsRead = -1;
}
return charsRead;
} catch (XMLParseException e) {
throw new IOException(e.getMessage());
}
}
/**
* Skips remaining data and closes the stream.
*
* @throws java.io.IOException
* if an error occurred reading the data
*/
public void close()
throws IOException
{
try {
int bufferLength = this.buffer.length();
for (;;) {
String str = "";
char ch;
if (this.bufferIndex >= bufferLength) {
str = XMLUtil.read(this.reader, '&');
ch = str.charAt(0);
} else {
ch = this.buffer.charAt(this.bufferIndex);
this.bufferIndex++;
continue; // don't interprete chars in the buffer
}
if (ch == '<') {
this.reader.unread(ch);
break;
}
if ((ch == '&') && (str.length() > 1)) {
if (str.charAt(1) != '#') {
XMLUtil.processEntity(str, this.reader, this.resolver);
}
}
}
} catch (XMLParseException e) {
throw new IOException(e.getMessage());
}
}
}
+157
View File
@@ -0,0 +1,157 @@
/* PIReader.java NanoXML/Java
*
* $Revision: 1.3 $
* $Date: 2002/01/04 21:03:28 $
* $Name: RELEASE_2_2_1 $
*
* This file is part of NanoXML 2 for Java.
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the
* use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
package processing.xml;
import java.io.Reader;
import java.io.IOException;
/**
* This reader reads data from another reader until the end of a processing
* instruction (?&gt;) has been encountered.
*
* @author Marc De Scheemaecker
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.3 $
*/
class PIReader
extends Reader
{
/**
* The encapsulated reader.
*/
private StdXMLReader reader;
/**
* True if the end of the stream has been reached.
*/
private boolean atEndOfData;
/**
* Creates the reader.
*
* @param reader the encapsulated reader
*/
PIReader(StdXMLReader reader)
{
this.reader = reader;
this.atEndOfData = false;
}
/**
* Cleans up the object when it's destroyed.
*/
protected void finalize()
throws Throwable
{
this.reader = null;
super.finalize();
}
/**
* Reads a block of data.
*
* @param buffer where to put the read data
* @param offset first position in buffer to put the data
* @param size maximum number of chars to read
*
* @return the number of chars read, or -1 if at EOF
*
* @throws java.io.IOException
* if an error occurred reading the data
*/
public int read(char[] buffer,
int offset,
int size)
throws IOException
{
if (this.atEndOfData) {
return -1;
}
int charsRead = 0;
if ((offset + size) > buffer.length) {
size = buffer.length - offset;
}
while (charsRead < size) {
char ch = this.reader.read();
if (ch == '?') {
char ch2 = this.reader.read();
if (ch2 == '>') {
this.atEndOfData = true;
break;
}
this.reader.unread(ch2);
}
buffer[charsRead] = ch;
charsRead++;
}
if (charsRead == 0) {
charsRead = -1;
}
return charsRead;
}
/**
* Skips remaining data and closes the stream.
*
* @throws java.io.IOException
* if an error occurred reading the data
*/
public void close()
throws IOException
{
while (! this.atEndOfData) {
char ch = this.reader.read();
if (ch == '?') {
char ch2 = this.reader.read();
if (ch2 == '>') {
this.atEndOfData = true;
}
}
}
}
}
+358
View File
@@ -0,0 +1,358 @@
/* StdXMLBuilder.java NanoXML/Java
*
* $Revision: 1.3 $
* $Date: 2002/01/04 21:03:28 $
* $Name: RELEASE_2_2_1 $
*
* This file is part of NanoXML 2 for Java.
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the
* use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
package processing.xml;
import java.io.IOException;
import java.io.Reader;
import java.util.Stack;
/**
* StdXMLBuilder is a concrete implementation of IXMLBuilder which creates a
* tree of IXMLElement from an XML data source.
*
* @see net.n3.nanoxml.XMLElement
*
* @author Marc De Scheemaecker
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.3 $
*/
public class StdXMLBuilder
{
/**
* This stack contains the current element and its parents.
*/
private Stack stack;
/**
* The root element of the parsed XML tree.
*/
private XMLElement root;
private XMLElement parent;
/**
* Prototype element for creating the tree.
*/
//private XMLElement prototype;
/**
* Creates the builder.
*/
public StdXMLBuilder()
{
this.stack = null;
this.root = null;
//this(new XMLElement());
}
public StdXMLBuilder(XMLElement parent)
{
this.parent = parent;
}
/**
* Creates the builder.
*
* @param prototype the prototype to use when building the tree.
*/
// public StdXMLBuilder(XMLElement prototype)
// {
// this.stack = null;
// this.root = null;
// this.prototype = prototype;
// }
/**
* Cleans up the object when it's destroyed.
*/
protected void finalize()
throws Throwable
{
//this.prototype = null;
this.root = null;
this.stack.clear();
this.stack = null;
super.finalize();
}
/**
* This method is called before the parser starts processing its input.
*
* @param systemID the system ID of the XML data source.
* @param lineNr the line on which the parsing starts.
*/
public void startBuilding(String systemID,
int lineNr)
{
this.stack = new Stack();
this.root = null;
}
/**
* This method is called when a processing instruction is encountered.
* PIs with target "xml" are handled by the parser.
*
* @param target the PI target.
* @param reader to read the data from the PI.
*/
public void newProcessingInstruction(String target,
Reader reader)
{
// nothing to do
}
/**
* This method is called when a new XML element is encountered.
*
* @see #endElement
*
* @param name the name of the element.
* @param nsPrefix the prefix used to identify the namespace. If no
* namespace has been specified, this parameter is null.
* @param nsURI the URI associated with the namespace. If no
* namespace has been specified, or no URI is
* associated with nsPrefix, this parameter is null.
* @param systemID the system ID of the XML data source.
* @param lineNr the line in the source where the element starts.
*/
public void startElement(String name,
String nsPrefix,
String nsURI,
String systemID,
int lineNr)
{
String fullName = name;
if (nsPrefix != null) {
fullName = nsPrefix + ':' + name;
}
//XMLElement elt = this.prototype.createElement(fullName, nsURI,
// systemID, lineNr);
// XMLElement elt = new XMLElement(fullName, nsURI, systemID, lineNr);
//
// if (this.stack.empty()) {
// this.root = elt;
// } else {
// XMLElement top = (XMLElement) this.stack.peek();
// top.addChild(elt);
// }
// stack.push(elt);
if (this.stack.empty()) {
//System.out.println("setting root");
parent.set(fullName, nsURI, systemID, lineNr);
stack.push(parent);
root = parent;
} else {
XMLElement top = (XMLElement) this.stack.peek();
//System.out.println("stack has " + top.getName());
XMLElement elt = new XMLElement(fullName, nsURI, systemID, lineNr);
top.addChild(elt);
stack.push(elt);
}
}
/**
* This method is called when the attributes of an XML element have been
* processed.
*
* @see #startElement
* @see #addAttribute
*
* @param name the name of the element.
* @param nsPrefix the prefix used to identify the namespace. If no
* namespace has been specified, this parameter is null.
* @param nsURI the URI associated with the namespace. If no
* namespace has been specified, or no URI is
* associated with nsPrefix, this parameter is null.
*/
public void elementAttributesProcessed(String name,
String nsPrefix,
String nsURI)
{
// nothing to do
}
/**
* This method is called when the end of an XML elemnt is encountered.
*
* @see #startElement
*
* @param name the name of the element.
* @param nsPrefix the prefix used to identify the namespace. If no
* namespace has been specified, this parameter is null.
* @param nsURI the URI associated with the namespace. If no
* namespace has been specified, or no URI is
* associated with nsPrefix, this parameter is null.
*/
public void endElement(String name,
String nsPrefix,
String nsURI)
{
XMLElement elt = (XMLElement) this.stack.pop();
if (elt.getChildCount() == 1) {
XMLElement child = elt.getChildAtIndex(0);
if (child.getName() == null) {
elt.setContent(child.getContent());
elt.removeChildAtIndex(0);
}
}
}
/**
* This method is called when a new attribute of an XML element is
* encountered.
*
* @param key the key (name) of the attribute.
* @param nsPrefix the prefix used to identify the namespace. If no
* namespace has been specified, this parameter is null.
* @param nsURI the URI associated with the namespace. If no
* namespace has been specified, or no URI is
* associated with nsPrefix, this parameter is null.
* @param value the value of the attribute.
* @param type the type of the attribute. If no type is known,
* "CDATA" is returned.
*
* @throws java.lang.Exception
* If an exception occurred while processing the event.
*/
public void addAttribute(String key,
String nsPrefix,
String nsURI,
String value,
String type)
throws Exception
{
String fullName = key;
if (nsPrefix != null) {
fullName = nsPrefix + ':' + key;
}
XMLElement top = (XMLElement) this.stack.peek();
if (top.hasAttribute(fullName)) {
throw new XMLParseException(top.getSystemID(),
top.getLineNr(),
"Duplicate attribute: " + key);
}
if (nsPrefix != null) {
top.setAttribute(fullName, nsURI, value);
} else {
top.setAttribute(fullName, value);
}
}
/**
* This method is called when a PCDATA element is encountered. A Java
* reader is supplied from which you can read the data. The reader will
* only read the data of the element. You don't need to check for
* boundaries. If you don't read the full element, the rest of the data
* is skipped. You also don't have to care about entities; they are
* resolved by the parser.
*
* @param reader the Java reader from which you can retrieve the data.
* @param systemID the system ID of the XML data source.
* @param lineNr the line in the source where the element starts.
*/
public void addPCData(Reader reader,
String systemID,
int lineNr)
{
int bufSize = 2048;
int sizeRead = 0;
StringBuffer str = new StringBuffer(bufSize);
char[] buf = new char[bufSize];
for (;;) {
if (sizeRead >= bufSize) {
bufSize *= 2;
str.ensureCapacity(bufSize);
}
int size;
try {
size = reader.read(buf);
} catch (IOException e) {
break;
}
if (size < 0) {
break;
}
str.append(buf, 0, size);
sizeRead += size;
}
//XMLElement elt = this.prototype.createElement(null, systemID, lineNr);
XMLElement elt = new XMLElement(null, null, systemID, lineNr);
elt.setContent(str.toString());
if (! this.stack.empty()) {
XMLElement top = (XMLElement) this.stack.peek();
top.addChild(elt);
}
}
/**
* Returns the result of the building process. This method is called just
* before the <I>parse</I> method of IXMLParser returns.
*
* @see net.n3.nanoxml.IXMLParser#parse
*
* @return the result of the building process.
*/
public Object getResult()
{
return this.root;
}
}
+684
View File
@@ -0,0 +1,684 @@
/* StdXMLParser.java NanoXML/Java
*
* $Revision: 1.5 $
* $Date: 2002/03/24 11:37:00 $
* $Name: RELEASE_2_2_1 $
*
* This file is part of NanoXML 2 for Java.
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the
* use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
package processing.xml;
import java.io.Reader;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
/**
* StdXMLParser is the core parser of NanoXML.
*
* @author Marc De Scheemaecker
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.5 $
*/
public class StdXMLParser {
/**
* The builder which creates the logical structure of the XML data.
*/
private StdXMLBuilder builder;
/**
* The reader from which the parser retrieves its data.
*/
private StdXMLReader reader;
/**
* The entity resolver.
*/
private XMLEntityResolver entityResolver;
/**
* The validator that will process entity references and validate the XML
* data.
*/
private XMLValidator validator;
/**
* Creates a new parser.
*/
public StdXMLParser()
{
this.builder = null;
this.validator = null;
this.reader = null;
this.entityResolver = new XMLEntityResolver();
}
/**
* Cleans up the object when it's destroyed.
*/
protected void finalize()
throws Throwable
{
this.builder = null;
this.reader = null;
this.entityResolver = null;
this.validator = null;
super.finalize();
}
/**
* Sets the builder which creates the logical structure of the XML data.
*
* @param builder the non-null builder
*/
public void setBuilder(StdXMLBuilder builder)
{
this.builder = builder;
}
/**
* Returns the builder which creates the logical structure of the XML data.
*
* @return the builder
*/
public StdXMLBuilder getBuilder()
{
return this.builder;
}
/**
* Sets the validator that validates the XML data.
*
* @param validator the non-null validator
*/
public void setValidator(XMLValidator validator)
{
this.validator = validator;
}
/**
* Returns the validator that validates the XML data.
*
* @return the validator
*/
public XMLValidator getValidator()
{
return this.validator;
}
/**
* Sets the entity resolver.
*
* @param resolver the non-null resolver
*/
public void setResolver(XMLEntityResolver resolver)
{
this.entityResolver = resolver;
}
/**
* Returns the entity resolver.
*
* @return the non-null resolver
*/
public XMLEntityResolver getResolver()
{
return this.entityResolver;
}
/**
* Sets the reader from which the parser retrieves its data.
*
* @param reader the reader
*/
public void setReader(StdXMLReader reader)
{
this.reader = reader;
}
/**
* Returns the reader from which the parser retrieves its data.
*
* @return the reader
*/
public StdXMLReader getReader()
{
return this.reader;
}
/**
* Parses the data and lets the builder create the logical data structure.
*
* @return the logical structure built by the builder
*
* @throws net.n3.nanoxml.XMLException
* if an error occurred reading or parsing the data
*/
public Object parse()
throws XMLException
{
try {
this.builder.startBuilding(this.reader.getSystemID(),
this.reader.getLineNr());
this.scanData();
return this.builder.getResult();
} catch (XMLException e) {
throw e;
} catch (Exception e) {
throw new XMLException(e);
}
}
/**
* Scans the XML data for elements.
*
* @throws java.lang.Exception
* if something went wrong
*/
protected void scanData() throws Exception {
while ((! this.reader.atEOF()) && (this.builder.getResult() == null)) {
String str = XMLUtil.read(this.reader, '&');
char ch = str.charAt(0);
if (ch == '&') {
XMLUtil.processEntity(str, this.reader, this.entityResolver);
continue;
}
switch (ch) {
case '<':
this.scanSomeTag(false, // don't allow CDATA
null, // no default namespace
new Properties());
break;
case ' ':
case '\t':
case '\r':
case '\n':
// skip whitespace
break;
default:
XMLUtil.errorInvalidInput(reader.getSystemID(),
reader.getLineNr(),
"`" + ch + "' (0x"
+ Integer.toHexString((int) ch)
+ ')');
}
}
}
/**
* Scans an XML tag.
*
* @param allowCDATA true if CDATA sections are allowed at this point
* @param defaultNamespace the default namespace URI (or null)
* @param namespaces list of defined namespaces
*
* @throws java.lang.Exception
* if something went wrong
*/
protected void scanSomeTag(boolean allowCDATA,
String defaultNamespace,
Properties namespaces)
throws Exception
{
String str = XMLUtil.read(this.reader, '&');
char ch = str.charAt(0);
if (ch == '&') {
XMLUtil.errorUnexpectedEntity(reader.getSystemID(),
reader.getLineNr(),
str);
}
switch (ch) {
case '?':
this.processPI();
break;
case '!':
this.processSpecialTag(allowCDATA);
break;
default:
this.reader.unread(ch);
this.processElement(defaultNamespace, namespaces);
}
}
/**
* Processes a "processing instruction".
*
* @throws java.lang.Exception
* if something went wrong
*/
protected void processPI()
throws Exception
{
XMLUtil.skipWhitespace(this.reader, null);
String target = XMLUtil.scanIdentifier(this.reader);
XMLUtil.skipWhitespace(this.reader, null);
Reader reader = new PIReader(this.reader);
if (! target.equalsIgnoreCase("xml")) {
this.builder.newProcessingInstruction(target, reader);
}
reader.close();
}
/**
* Processes a tag that starts with a bang (&lt;!...&gt;).
*
* @param allowCDATA true if CDATA sections are allowed at this point
*
* @throws java.lang.Exception
* if something went wrong
*/
protected void processSpecialTag(boolean allowCDATA)
throws Exception
{
String str = XMLUtil.read(this.reader, '&');
char ch = str.charAt(0);
if (ch == '&') {
XMLUtil.errorUnexpectedEntity(reader.getSystemID(),
reader.getLineNr(),
str);
}
switch (ch) {
case '[':
if (allowCDATA) {
this.processCDATA();
} else {
XMLUtil.errorUnexpectedCDATA(reader.getSystemID(),
reader.getLineNr());
}
return;
case 'D':
this.processDocType();
return;
case '-':
XMLUtil.skipComment(this.reader);
return;
}
}
/**
* Processes a CDATA section.
*
* @throws java.lang.Exception
* if something went wrong
*/
protected void processCDATA()
throws Exception
{
if (! XMLUtil.checkLiteral(this.reader, "CDATA[")) {
XMLUtil.errorExpectedInput(reader.getSystemID(),
reader.getLineNr(),
"<![[CDATA[");
}
this.validator.PCDataAdded(this.reader.getSystemID(),
this.reader.getLineNr());
Reader reader = new CDATAReader(this.reader);
this.builder.addPCData(reader, this.reader.getSystemID(),
this.reader.getLineNr());
reader.close();
}
/**
* Processes a document type declaration.
*
* @throws java.lang.Exception
* if an error occurred reading or parsing the data
*/
protected void processDocType() throws Exception {
if (! XMLUtil.checkLiteral(this.reader, "OCTYPE")) {
XMLUtil.errorExpectedInput(reader.getSystemID(),
reader.getLineNr(),
"<!DOCTYPE");
return;
}
XMLUtil.skipWhitespace(this.reader, null);
String systemID = null;
StringBuffer publicID = new StringBuffer();
/*String rootElement =*/ XMLUtil.scanIdentifier(this.reader);
//System.out.println("rootElement is " + rootElement);
XMLUtil.skipWhitespace(this.reader, null);
char ch = this.reader.read();
if (ch == 'P') {
systemID = XMLUtil.scanPublicID(publicID, reader);
XMLUtil.skipWhitespace(this.reader, null);
ch = this.reader.read();
} else if (ch == 'S') {
systemID = XMLUtil.scanSystemID(reader);
XMLUtil.skipWhitespace(this.reader, null);
ch = this.reader.read();
}
if (ch == '[') {
this.validator.parseDTD(publicID.toString(),
this.reader,
this.entityResolver,
false);
XMLUtil.skipWhitespace(this.reader, null);
ch = this.reader.read();
}
if (ch != '>') {
XMLUtil.errorExpectedInput(reader.getSystemID(),
reader.getLineNr(),
"`>'");
}
if (false) { // TODO currently disabled
if (systemID != null) {
Reader reader = this.reader.openStream(publicID.toString(),
systemID);
this.reader.startNewStream(reader);
this.reader.setSystemID(systemID);
this.reader.setPublicID(publicID.toString());
this.validator.parseDTD(publicID.toString(),
this.reader,
this.entityResolver,
true);
}
}
}
/**
* Processes a regular element.
*
* @param defaultNamespace the default namespace URI (or null)
* @param namespaces list of defined namespaces
*
* @throws java.lang.Exception
* if something went wrong
*/
protected void processElement(String defaultNamespace,
Properties namespaces)
throws Exception
{
String fullName = XMLUtil.scanIdentifier(this.reader);
String name = fullName;
XMLUtil.skipWhitespace(this.reader, null);
String prefix = null;
int colonIndex = name.indexOf(':');
if (colonIndex > 0) {
prefix = name.substring(0, colonIndex);
name = name.substring(colonIndex + 1);
}
Vector attrNames = new Vector();
Vector attrValues = new Vector();
Vector attrTypes = new Vector();
this.validator.elementStarted(fullName,
this.reader.getSystemID(),
this.reader.getLineNr());
char ch;
for (;;) {
ch = this.reader.read();
if ((ch == '/') || (ch == '>')) {
break;
}
this.reader.unread(ch);
this.processAttribute(attrNames, attrValues, attrTypes);
XMLUtil.skipWhitespace(this.reader, null);
}
Properties extraAttributes = new Properties();
this.validator.elementAttributesProcessed(fullName,
extraAttributes,
this.reader.getSystemID(),
this.reader.getLineNr());
Enumeration en = extraAttributes.keys();
while (en.hasMoreElements()) {
String key = (String) en.nextElement();
String value = extraAttributes.getProperty(key);
attrNames.addElement(key);
attrValues.addElement(value);
attrTypes.addElement("CDATA");
}
for (int i = 0; i < attrNames.size(); i++) {
String key = (String) attrNames.elementAt(i);
String value = (String) attrValues.elementAt(i);
//String type = (String) attrTypes.elementAt(i);
if (key.equals("xmlns")) {
defaultNamespace = value;
} else if (key.startsWith("xmlns:")) {
namespaces.put(key.substring(6), value);
}
}
if (prefix == null) {
this.builder.startElement(name, prefix, defaultNamespace,
this.reader.getSystemID(),
this.reader.getLineNr());
} else {
this.builder.startElement(name, prefix,
namespaces.getProperty(prefix),
this.reader.getSystemID(),
this.reader.getLineNr());
}
for (int i = 0; i < attrNames.size(); i++) {
String key = (String) attrNames.elementAt(i);
if (key.startsWith("xmlns")) {
continue;
}
String value = (String) attrValues.elementAt(i);
String type = (String) attrTypes.elementAt(i);
colonIndex = key.indexOf(':');
if (colonIndex > 0) {
String attPrefix = key.substring(0, colonIndex);
key = key.substring(colonIndex + 1);
this.builder.addAttribute(key, attPrefix,
namespaces.getProperty(attPrefix),
value, type);
} else {
this.builder.addAttribute(key, null, null, value, type);
}
}
if (prefix == null) {
this.builder.elementAttributesProcessed(name, prefix,
defaultNamespace);
} else {
this.builder.elementAttributesProcessed(name, prefix,
namespaces
.getProperty(prefix));
}
if (ch == '/') {
if (this.reader.read() != '>') {
XMLUtil.errorExpectedInput(reader.getSystemID(),
reader.getLineNr(),
"`>'");
}
this.validator.elementEnded(name,
this.reader.getSystemID(),
this.reader.getLineNr());
if (prefix == null) {
this.builder.endElement(name, prefix, defaultNamespace);
} else {
this.builder.endElement(name, prefix,
namespaces.getProperty(prefix));
}
return;
}
StringBuffer buffer = new StringBuffer(16);
for (;;) {
buffer.setLength(0);
String str;
for (;;) {
XMLUtil.skipWhitespace(this.reader, buffer);
str = XMLUtil.read(this.reader, '&');
if ((str.charAt(0) == '&') && (str.charAt(1) != '#')) {
XMLUtil.processEntity(str, this.reader,
this.entityResolver);
} else {
break;
}
}
if (str.charAt(0) == '<') {
str = XMLUtil.read(this.reader, '\0');
if (str.charAt(0) == '/') {
XMLUtil.skipWhitespace(this.reader, null);
str = XMLUtil.scanIdentifier(this.reader);
if (! str.equals(fullName)) {
XMLUtil.errorWrongClosingTag(reader.getSystemID(),
reader.getLineNr(),
name, str);
}
XMLUtil.skipWhitespace(this.reader, null);
if (this.reader.read() != '>') {
XMLUtil.errorClosingTagNotEmpty(reader.getSystemID(),
reader.getLineNr());
}
this.validator.elementEnded(fullName,
this.reader.getSystemID(),
this.reader.getLineNr());
if (prefix == null) {
this.builder.endElement(name, prefix, defaultNamespace);
} else {
this.builder.endElement(name, prefix,
namespaces.getProperty(prefix));
}
break;
} else { // <[^/]
this.reader.unread(str.charAt(0));
this.scanSomeTag(true, //CDATA allowed
defaultNamespace,
(Properties) namespaces.clone());
}
} else { // [^<]
if (str.charAt(0) == '&') {
ch = XMLUtil.processCharLiteral(str);
buffer.append(ch);
} else {
reader.unread(str.charAt(0));
}
this.validator.PCDataAdded(this.reader.getSystemID(),
this.reader.getLineNr());
Reader r = new ContentReader(this.reader,
this.entityResolver,
buffer.toString());
this.builder.addPCData(r, this.reader.getSystemID(),
this.reader.getLineNr());
r.close();
}
}
}
/**
* Processes an attribute of an element.
*
* @param attrNames contains the names of the attributes.
* @param attrValues contains the values of the attributes.
* @param attrTypes contains the types of the attributes.
*
* @throws java.lang.Exception
* if something went wrong
*/
protected void processAttribute(Vector attrNames,
Vector attrValues,
Vector attrTypes)
throws Exception
{
String key = XMLUtil.scanIdentifier(this.reader);
XMLUtil.skipWhitespace(this.reader, null);
if (! XMLUtil.read(this.reader, '&').equals("=")) {
XMLUtil.errorExpectedInput(reader.getSystemID(),
reader.getLineNr(),
"`='");
}
XMLUtil.skipWhitespace(this.reader, null);
String value = XMLUtil.scanString(this.reader, '&',
this.entityResolver);
attrNames.addElement(key);
attrValues.addElement(value);
attrTypes.addElement("CDATA");
this.validator.attributeAdded(key, value,
this.reader.getSystemID(),
this.reader.getLineNr());
}
}
+626
View File
@@ -0,0 +1,626 @@
/* StdXMLReader.java NanoXML/Java
*
* $Revision: 1.4 $
* $Date: 2002/01/04 21:03:28 $
* $Name: RELEASE_2_2_1 $
*
* This file is part of NanoXML 2 for Java.
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the
* use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
package processing.xml;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
//import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.LineNumberReader;
import java.io.PushbackReader;
import java.io.PushbackInputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Stack;
/**
* StdXMLReader reads the data to be parsed.
*
* @author Marc De Scheemaecker
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
*/
public class StdXMLReader
{
/**
* A stacked reader.
*
* @author Marc De Scheemaecker
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
*/
private class StackedReader
{
PushbackReader pbReader;
LineNumberReader lineReader;
URL systemId;
String publicId;
}
/**
* The stack of readers.
*/
private Stack readers;
/**
* The current push-back reader.
*/
private StackedReader currentReader;
/**
* Creates a new reader using a string as input.
*
* @param str the string containing the XML data
*/
public static StdXMLReader stringReader(String str)
{
return new StdXMLReader(new StringReader(str));
}
/**
* Creates a new reader using a file as input.
*
* @param filename the name of the file containing the XML data
*
* @throws java.io.FileNotFoundException
* if the file could not be found
* @throws java.io.IOException
* if an I/O error occurred
*/
public static StdXMLReader fileReader(String filename)
throws FileNotFoundException,
IOException
{
StdXMLReader r = new StdXMLReader(new FileInputStream(filename));
r.setSystemID(filename);
for (int i = 0; i < r.readers.size(); i++) {
StackedReader sr = (StackedReader) r.readers.elementAt(i);
sr.systemId = r.currentReader.systemId;
}
return r;
}
/**
* Initializes the reader from a system and public ID.
*
* @param publicID the public ID which may be null.
* @param systemID the non-null system ID.
*
* @throws MalformedURLException
* if the system ID does not contain a valid URL
* @throws FileNotFoundException
* if the system ID refers to a local file which does not exist
* @throws IOException
* if an error occurred opening the stream
*/
public StdXMLReader(String publicID,
String systemID)
throws MalformedURLException,
FileNotFoundException,
IOException
{
URL systemIDasURL = null;
try {
systemIDasURL = new URL(systemID);
} catch (MalformedURLException e) {
systemID = "file:" + systemID;
try {
systemIDasURL = new URL(systemID);
} catch (MalformedURLException e2) {
throw e;
}
}
this.currentReader = new StackedReader();
this.readers = new Stack();
Reader reader = this.openStream(publicID, systemIDasURL.toString());
this.currentReader.lineReader = new LineNumberReader(reader);
this.currentReader.pbReader
= new PushbackReader(this.currentReader.lineReader, 2);
}
/**
* Initializes the XML reader.
*
* @param reader the input for the XML data.
*/
public StdXMLReader(Reader reader)
{
this.currentReader = new StackedReader();
this.readers = new Stack();
this.currentReader.lineReader = new LineNumberReader(reader);
this.currentReader.pbReader
= new PushbackReader(this.currentReader.lineReader, 2);
this.currentReader.publicId = "";
try {
this.currentReader.systemId = new URL("file:.");
} catch (MalformedURLException e) {
// never happens
}
}
/**
* Cleans up the object when it's destroyed.
*/
protected void finalize()
throws Throwable
{
this.currentReader.lineReader = null;
this.currentReader.pbReader = null;
this.currentReader.systemId = null;
this.currentReader.publicId = null;
this.currentReader = null;
this.readers.clear();
super.finalize();
}
/**
* Scans the encoding from an &lt;?xml...?&gt; tag.
*
* @param str the first tag in the XML data.
*
* @return the encoding, or null if no encoding has been specified.
*/
protected String getEncoding(String str)
{
if (! str.startsWith("<?xml")) {
return null;
}
int index = 5;
while (index < str.length()) {
StringBuffer key = new StringBuffer();
while ((index < str.length()) && (str.charAt(index) <= ' ')) {
index++;
}
while ((index < str.length())
&& (str.charAt(index) >= 'a')
&& (str.charAt(index) <= 'z')) {
key.append(str.charAt(index));
index++;
}
while ((index < str.length()) && (str.charAt(index) <= ' ')) {
index++;
}
if ((index >= str.length()) || (str.charAt(index) != '=')) {
break;
}
while ((index < str.length()) && (str.charAt(index) != '\'')
&& (str.charAt(index) != '"')) {
index++;
}
if (index >= str.length()) {
break;
}
char delimiter = str.charAt(index);
index++;
int index2 = str.indexOf(delimiter, index);
if (index2 < 0) {
break;
}
if (key.toString().equals("encoding")) {
return str.substring(index, index2);
}
index = index2 + 1;
}
return null;
}
/**
* Converts a stream to a reader while detecting the encoding.
*
* @param stream the input for the XML data.
* @param charsRead buffer where to put characters that have been read
*
* @throws java.io.IOException
* if an I/O error occurred
*/
protected Reader stream2reader(InputStream stream,
StringBuffer charsRead)
throws IOException
{
PushbackInputStream pbstream = new PushbackInputStream(stream);
int b = pbstream.read();
switch (b) {
case 0x00:
case 0xFE:
case 0xFF:
pbstream.unread(b);
return new InputStreamReader(pbstream, "UTF-16");
case 0xEF:
for (int i = 0; i < 2; i++) {
pbstream.read();
}
return new InputStreamReader(pbstream, "UTF-8");
case 0x3C:
b = pbstream.read();
charsRead.append('<');
while ((b > 0) && (b != 0x3E)) {
charsRead.append((char) b);
b = pbstream.read();
}
if (b > 0) {
charsRead.append((char) b);
}
String encoding = this.getEncoding(charsRead.toString());
if (encoding == null) {
return new InputStreamReader(pbstream, "UTF-8");
}
charsRead.setLength(0);
try {
return new InputStreamReader(pbstream, encoding);
} catch (UnsupportedEncodingException e) {
return new InputStreamReader(pbstream, "UTF-8");
}
default:
charsRead.append((char) b);
return new InputStreamReader(pbstream, "UTF-8");
}
}
/**
* Initializes the XML reader.
*
* @param stream the input for the XML data.
*
* @throws java.io.IOException
* if an I/O error occurred
*/
public StdXMLReader(InputStream stream)
throws IOException
{
// unused?
//PushbackInputStream pbstream = new PushbackInputStream(stream);
StringBuffer charsRead = new StringBuffer();
Reader reader = this.stream2reader(stream, charsRead);
this.currentReader = new StackedReader();
this.readers = new Stack();
this.currentReader.lineReader = new LineNumberReader(reader);
this.currentReader.pbReader
= new PushbackReader(this.currentReader.lineReader, 2);
this.currentReader.publicId = "";
try {
this.currentReader.systemId = new URL("file:.");
} catch (MalformedURLException e) {
// never happens
}
this.startNewStream(new StringReader(charsRead.toString()));
}
/**
* Reads a character.
*
* @return the character
*
* @throws java.io.IOException
* if no character could be read
*/
public char read()
throws IOException
{
int ch = this.currentReader.pbReader.read();
while (ch < 0) {
if (this.readers.empty()) {
throw new IOException("Unexpected EOF");
}
this.currentReader.pbReader.close();
this.currentReader = (StackedReader) this.readers.pop();
ch = this.currentReader.pbReader.read();
}
return (char) ch;
}
/**
* Returns true if the current stream has no more characters left to be
* read.
*
* @throws java.io.IOException
* if an I/O error occurred
*/
public boolean atEOFOfCurrentStream()
throws IOException
{
int ch = this.currentReader.pbReader.read();
if (ch < 0) {
return true;
} else {
this.currentReader.pbReader.unread(ch);
return false;
}
}
/**
* Returns true if there are no more characters left to be read.
*
* @throws java.io.IOException
* if an I/O error occurred
*/
public boolean atEOF()
throws IOException
{
int ch = this.currentReader.pbReader.read();
while (ch < 0) {
if (this.readers.empty()) {
return true;
}
this.currentReader.pbReader.close();
this.currentReader = (StackedReader) this.readers.pop();
ch = this.currentReader.pbReader.read();
}
this.currentReader.pbReader.unread(ch);
return false;
}
/**
* Pushes the last character read back to the stream.
*
* @param ch the character to push back.
*
* @throws java.io.IOException
* if an I/O error occurred
*/
public void unread(char ch)
throws IOException
{
this.currentReader.pbReader.unread(ch);
}
/**
* Opens a stream from a public and system ID.
*
* @param publicID the public ID, which may be null
* @param systemID the system ID, which is never null
*
* @throws java.net.MalformedURLException
* if the system ID does not contain a valid URL
* @throws java.io.FileNotFoundException
* if the system ID refers to a local file which does not exist
* @throws java.io.IOException
* if an error occurred opening the stream
*/
public Reader openStream(String publicID,
String systemID)
throws MalformedURLException,
FileNotFoundException,
IOException
{
URL url = new URL(this.currentReader.systemId, systemID);
if (url.getRef() != null) {
String ref = url.getRef();
if (url.getFile().length() > 0) {
url = new URL(url.getProtocol(), url.getHost(), url.getPort(),
url.getFile());
url = new URL("jar:" + url + '!' + ref);
} else {
url = StdXMLReader.class.getResource(ref);
}
}
this.currentReader.publicId = publicID;
this.currentReader.systemId = url;
StringBuffer charsRead = new StringBuffer();
Reader reader = this.stream2reader(url.openStream(), charsRead);
if (charsRead.length() == 0) {
return reader;
}
String charsReadStr = charsRead.toString();
PushbackReader pbreader = new PushbackReader(reader,
charsReadStr.length());
for (int i = charsReadStr.length() - 1; i >= 0; i--) {
pbreader.unread(charsReadStr.charAt(i));
}
return pbreader;
}
/**
* Starts a new stream from a Java reader. The new stream is used
* temporary to read data from. If that stream is exhausted, control
* returns to the parent stream.
*
* @param reader the non-null reader to read the new data from
*/
public void startNewStream(Reader reader)
{
this.startNewStream(reader, false);
}
/**
* Starts a new stream from a Java reader. The new stream is used
* temporary to read data from. If that stream is exhausted, control
* returns to the parent stream.
*
* @param reader the non-null reader to read the new data from
* @param isInternalEntity true if the reader is produced by resolving
* an internal entity
*/
public void startNewStream(Reader reader,
boolean isInternalEntity)
{
StackedReader oldReader = this.currentReader;
this.readers.push(this.currentReader);
this.currentReader = new StackedReader();
if (isInternalEntity) {
this.currentReader.lineReader = null;
this.currentReader.pbReader = new PushbackReader(reader, 2);
} else {
this.currentReader.lineReader = new LineNumberReader(reader);
this.currentReader.pbReader
= new PushbackReader(this.currentReader.lineReader, 2);
}
this.currentReader.systemId = oldReader.systemId;
this.currentReader.publicId = oldReader.publicId;
}
/**
* Returns the current "level" of the stream on the stack of streams.
*/
public int getStreamLevel()
{
return this.readers.size();
}
/**
* Returns the line number of the data in the current stream.
*/
public int getLineNr()
{
if (this.currentReader.lineReader == null) {
StackedReader sr = (StackedReader) this.readers.peek();
if (sr.lineReader == null) {
return 0;
} else {
return sr.lineReader.getLineNumber() + 1;
}
}
return this.currentReader.lineReader.getLineNumber() + 1;
}
/**
* Sets the system ID of the current stream.
*
* @param systemID the system ID
*
* @throws java.net.MalformedURLException
* if the system ID does not contain a valid URL
*/
public void setSystemID(String systemID)
throws MalformedURLException
{
this.currentReader.systemId = new URL(this.currentReader.systemId,
systemID);
}
/**
* Sets the public ID of the current stream.
*
* @param publicID the public ID
*/
public void setPublicID(String publicID)
{
this.currentReader.publicId = publicID;
}
/**
* Returns the current system ID.
*/
public String getSystemID()
{
return this.currentReader.systemId.toString();
}
/**
* Returns the current public ID.
*/
public String getPublicID()
{
return this.currentReader.publicId;
}
}
+153
View File
@@ -0,0 +1,153 @@
/* XMLAttribute.java NanoXML/Java
*
* $Revision: 1.4 $
* $Date: 2002/01/04 21:03:29 $
* $Name: RELEASE_2_2_1 $
*
* This file is part of NanoXML 2 for Java.
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the
* use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
package processing.xml;
/**
* An attribute in an XML element. This is an internal class.
*
* @see net.n3.nanoxml.XMLElement
*
* @author Marc De Scheemaecker
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
*/
class XMLAttribute
{
/**
* The full name of the attribute.
*/
private String fullName;
/**
* The short name of the attribute.
*/
private String name;
/**
* The namespace URI of the attribute.
*/
private String namespace;
/**
* The value of the attribute.
*/
private String value;
/**
* The type of the attribute.
*/
private String type;
/**
* Creates a new attribute.
*
* @param fullName the non-null full name
* @param name the non-null short name
* @param namespace the namespace URI, which may be null
* @param value the value of the attribute
* @param type the type of the attribute
*/
XMLAttribute(String fullName,
String name,
String namespace,
String value,
String type)
{
this.fullName = fullName;
this.name = name;
this.namespace = namespace;
this.value = value;
this.type = type;
}
/**
* Returns the full name of the attribute.
*/
String getFullName()
{
return this.fullName;
}
/**
* Returns the short name of the attribute.
*/
String getName()
{
return this.name;
}
/**
* Returns the namespace of the attribute.
*/
String getNamespace()
{
return this.namespace;
}
/**
* Returns the value of the attribute.
*/
String getValue()
{
return this.value;
}
/**
* Sets the value of the attribute.
*
* @param value the new value.
*/
void setValue(String value)
{
this.value = value;
}
/**
* Returns the type of the attribute.
*
* @param type the new type.
*/
String getType()
{
return this.type;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,173 @@
/* XMLEntityResolver.java NanoXML/Java
*
* $Revision: 1.4 $
* $Date: 2002/01/04 21:03:29 $
* $Name: RELEASE_2_2_1 $
*
* This file is part of NanoXML 2 for Java.
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the
* use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
package processing.xml;
import java.util.Hashtable;
import java.io.Reader;
import java.io.StringReader;
/**
* An XMLEntityResolver resolves entities.
*
* @author Marc De Scheemaecker
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
*/
public class XMLEntityResolver
{
/**
* The entities.
*/
private Hashtable entities;
/**
* Initializes the resolver.
*/
public XMLEntityResolver()
{
this.entities = new Hashtable();
this.entities.put("amp", "&#38;");
this.entities.put("quot", "&#34;");
this.entities.put("apos", "&#39;");
this.entities.put("lt", "&#60;");
this.entities.put("gt", "&#62;");
}
/**
* Cleans up the object when it's destroyed.
*/
protected void finalize()
throws Throwable
{
this.entities.clear();
this.entities = null;
super.finalize();
}
/**
* Adds an internal entity.
*
* @param name the name of the entity.
* @param value the value of the entity.
*/
public void addInternalEntity(String name,
String value)
{
if (! this.entities.containsKey(name)) {
this.entities.put(name, value);
}
}
/**
* Adds an external entity.
*
* @param name the name of the entity.
* @param publicID the public ID of the entity, which may be null.
* @param systemID the system ID of the entity.
*/
public void addExternalEntity(String name,
String publicID,
String systemID)
{
if (! this.entities.containsKey(name)) {
this.entities.put(name, new String[] { publicID, systemID } );
}
}
/**
* Returns a Java reader containing the value of an entity.
*
* @param xmlReader the current XML reader
* @param name the name of the entity.
*
* @return the reader, or null if the entity could not be resolved.
*/
public Reader getEntity(StdXMLReader xmlReader,
String name)
throws XMLParseException
{
Object obj = this.entities.get(name);
if (obj == null) {
return null;
} else if (obj instanceof java.lang.String) {
return new StringReader((String)obj);
} else {
String[] id = (String[]) obj;
return this.openExternalEntity(xmlReader, id[0], id[1]);
}
}
/**
* Returns true if an entity is external.
*
* @param name the name of the entity.
*/
public boolean isExternalEntity(String name)
{
Object obj = this.entities.get(name);
return ! (obj instanceof java.lang.String);
}
/**
* Opens an external entity.
*
* @param xmlReader the current XML reader
* @param publicID the public ID, which may be null
* @param systemID the system ID
*
* @return the reader, or null if the reader could not be created/opened
*/
protected Reader openExternalEntity(StdXMLReader xmlReader,
String publicID,
String systemID)
throws XMLParseException
{
String parentSystemID = xmlReader.getSystemID();
try {
return xmlReader.openStream(publicID, systemID);
} catch (Exception e) {
throw new XMLParseException(parentSystemID,
xmlReader.getLineNr(),
"Could not open external entity "
+ "at system ID: " + systemID);
}
}
}
+286
View File
@@ -0,0 +1,286 @@
/* XMLException.java NanoXML/Java
*
* $Revision: 1.4 $
* $Date: 2002/01/04 21:03:29 $
* $Name: RELEASE_2_2_1 $
*
* This file is part of NanoXML 2 for Java.
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the
* use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
package processing.xml;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* An XMLException is thrown when an exception occurred while processing the
* XML data.
*
* @author Marc De Scheemaecker
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
*/
public class XMLException
extends Exception
{
/**
* The message of the exception.
*/
private String msg;
/**
* The system ID of the XML data where the exception occurred.
*/
private String systemID;
/**
* The line number in the XML data where the exception occurred.
*/
private int lineNr;
/**
* Encapsulated exception.
*/
private Exception encapsulatedException;
/**
* Creates a new exception.
*
* @param msg the message of the exception.
*/
public XMLException(String msg)
{
this(null, -1, null, msg, false);
}
/**
* Creates a new exception.
*
* @param e the encapsulated exception.
*/
public XMLException(Exception e)
{
this(null, -1, e, "Nested Exception", false);
}
/**
* Creates a new exception.
*
* @param systemID the system ID of the XML data where the exception
* occurred
* @param lineNr the line number in the XML data where the exception
* occurred.
* @param e the encapsulated exception.
*/
public XMLException(String systemID,
int lineNr,
Exception e)
{
this(systemID, lineNr, e, "Nested Exception", true);
}
/**
* Creates a new exception.
*
* @param systemID the system ID of the XML data where the exception
* occurred
* @param lineNr the line number in the XML data where the exception
* occurred.
* @param msg the message of the exception.
*/
public XMLException(String systemID,
int lineNr,
String msg)
{
this(systemID, lineNr, null, msg, true);
}
/**
* Creates a new exception.
*
* @param systemID the system ID from where the data came
* @param lineNr the line number in the XML data where the exception
* occurred.
* @param e the encapsulated exception.
* @param msg the message of the exception.
* @param reportParams true if the systemID, lineNr and e params need to be
* appended to the message
*/
public XMLException(String systemID,
int lineNr,
Exception e,
String msg,
boolean reportParams)
{
super(XMLException.buildMessage(systemID, lineNr, e, msg,
reportParams));
this.systemID = systemID;
this.lineNr = lineNr;
this.encapsulatedException = e;
this.msg = XMLException.buildMessage(systemID, lineNr, e, msg,
reportParams);
}
/**
* Builds the exception message
*
* @param systemID the system ID from where the data came
* @param lineNr the line number in the XML data where the exception
* occurred.
* @param e the encapsulated exception.
* @param msg the message of the exception.
* @param reportParams true if the systemID, lineNr and e params need to be
* appended to the message
*/
private static String buildMessage(String systemID,
int lineNr,
Exception e,
String msg,
boolean reportParams)
{
String str = msg;
if (reportParams) {
if (systemID != null) {
str += ", SystemID='" + systemID + "'";
}
if (lineNr >= 0) {
str += ", Line=" + lineNr;
}
if (e != null) {
str += ", Exception: " + e;
}
}
return str;
}
/**
* Cleans up the object when it's destroyed.
*/
protected void finalize()
throws Throwable
{
this.systemID = null;
this.encapsulatedException = null;
super.finalize();
}
/**
* Returns the system ID of the XML data where the exception occurred.
* If there is no system ID known, null is returned.
*/
public String getSystemID()
{
return this.systemID;
}
/**
* Returns the line number in the XML data where the exception occurred.
* If there is no line number known, -1 is returned.
*/
public int getLineNr()
{
return this.lineNr;
}
/**
* Returns the encapsulated exception, or null if no exception is
* encapsulated.
*/
public Exception getException()
{
return this.encapsulatedException;
}
/**
* Dumps the exception stack to a print writer.
*
* @param writer the print writer
*/
public void printStackTrace(PrintWriter writer)
{
super.printStackTrace(writer);
if (this.encapsulatedException != null) {
writer.println("*** Nested Exception:");
this.encapsulatedException.printStackTrace(writer);
}
}
/**
* Dumps the exception stack to an output stream.
*
* @param stream the output stream
*/
public void printStackTrace(PrintStream stream)
{
super.printStackTrace(stream);
if (this.encapsulatedException != null) {
stream.println("*** Nested Exception:");
this.encapsulatedException.printStackTrace(stream);
}
}
/**
* Dumps the exception stack to System.err.
*/
public void printStackTrace()
{
super.printStackTrace();
if (this.encapsulatedException != null) {
System.err.println("*** Nested Exception:");
this.encapsulatedException.printStackTrace();
}
}
/**
* Returns a string representation of the exception.
*/
public String toString()
{
return this.msg;
}
}
+54 -110
View File
@@ -1,125 +1,69 @@
/*
This code is from NanoXML 2.2.3 Lite
Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
Additional modifications Copyright (c) 2006 Ben Fry and Casey Reas
to make the code better-suited for use with Processing.
Original license notice from Marc De Scheemaecker:
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in
a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* XMLParseException.java NanoXML/Java
*
* $Revision: 1.3 $
* $Date: 2002/01/04 21:03:29 $
* $Name: RELEASE_2_2_1 $
*
* This file is part of NanoXML 2 for Java.
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the
* use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
package processing.xml;
/**
* An XMLParseException is thrown when an error occures while parsing an XML
* string.
*
* @see processing.xml.XMLElement
* An XMLParseException is thrown when the XML passed to the XML parser is not
* well-formed.
*
* @author Marc De Scheemaecker
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.3 $
*/
public class XMLParseException
extends RuntimeException
extends XMLException
{
/**
* Indicates that no line number has been associated with this exception.
*/
public static final int NO_LINE = -1;
/**
* Creates a new exception.
*
* @param msg the message of the exception.
*/
public XMLParseException(String msg)
{
super(msg);
}
/**
* The line number in the source code where the error occurred, or
* <code>NO_LINE</code> if the line number is unknown.
*
* <dl><dt><b>Invariants:</b></dt><dd>
* <ul><li><code>lineNumber &gt 0 || lineNumber == NO_LINE</code>
* </ul></dd></dl>
*/
private int lineNumber;
/**
* Creates an exception.
*
* @param name The name of the element where the error is located.
* @param message A message describing what went wrong.
*
* </dl><dl><dt><b>Preconditions:</b></dt><dd>
* <ul><li><code>message != null</code>
* </ul></dd></dl>
*
* <dl><dt><b>Postconditions:</b></dt><dd>
* <ul><li>getLineNumber() => NO_LINE
* </ul></dd></dl><dl>
*/
public XMLParseException(String name,
String message)
{
super("XML Parse Exception during parsing of "
+ ((name == null) ? "the XML definition"
: ("a " + name + " element"))
+ ": " + message);
this.lineNumber = XMLParseException.NO_LINE;
}
/**
* Creates an exception.
*
* @param name The name of the element where the error is located.
* @param lineNumber The number of the line in the input.
* @param message A message describing what went wrong.
*
* </dl><dl><dt><b>Preconditions:</b></dt><dd>
* <ul><li><code>message != null</code>
* <li><code>lineNumber &gt; 0</code>
* </ul></dd></dl>
*
* <dl><dt><b>Postconditions:</b></dt><dd>
* <ul><li>getLineNumber() => lineNumber
* </ul></dd></dl><dl>
*/
public XMLParseException(String name,
int lineNumber,
String message)
{
super("XML Parse Exception during parsing of "
+ ((name == null) ? "the XML definition"
: ("a " + name + " element"))
+ " at line " + lineNumber + ": " + message);
this.lineNumber = lineNumber;
}
/**
* Where the error occurred, or <code>NO_LINE</code> if the line number is
* unknown.
*
* @see processing.xml.XMLParseException#NO_LINE
*/
public int getLineNumber()
{
return this.lineNumber;
}
/**
* Creates a new exception.
*
* @param systemID the system ID from where the data came
* @param lineNr the line number in the XML data where the exception
* occurred.
* @param msg the message of the exception.
*/
public XMLParseException(String systemID,
int lineNr,
String msg)
{
super(systemID, lineNr, null, msg, true);
}
}
+756
View File
@@ -0,0 +1,756 @@
/* XMLUtil.java NanoXML/Java
*
* $Revision: 1.5 $
* $Date: 2002/02/03 21:19:38 $
* $Name: RELEASE_2_2_1 $
*
* This file is part of NanoXML 2 for Java.
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the
* use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
package processing.xml;
import java.io.IOException;
import java.io.Reader;
/**
* Utility methods for NanoXML.
*
* @author Marc De Scheemaecker
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.5 $
*/
class XMLUtil
{
/**
* Skips the remainder of a comment.
* It is assumed that &lt;!- is already read.
*
* @param reader the reader
*
* @throws java.io.IOException
* if an error occurred reading the data
*/
static void skipComment(StdXMLReader reader)
throws IOException,
XMLParseException
{
if (reader.read() != '-') {
XMLUtil.errorExpectedInput(reader.getSystemID(),
reader.getLineNr(),
"<!--");
}
int dashesRead = 0;
for (;;) {
char ch = reader.read();
switch (ch) {
case '-':
dashesRead++;
break;
case '>':
if (dashesRead == 2) {
return;
}
default:
dashesRead = 0;
}
}
}
/**
* Skips the remainder of the current XML tag.
*
* @param reader the reader
*
* @throws java.io.IOException
* if an error occurred reading the data
*/
static void skipTag(StdXMLReader reader)
throws IOException,
XMLParseException
{
int level = 1;
while (level > 0) {
char ch = reader.read();
switch (ch) {
case '<':
++level;
break;
case '>':
--level;
break;
}
}
}
/**
* Scans a public ID.
*
* @param publicID will contain the public ID
* @param reader the reader
*
* @return the system ID
*
* @throws java.io.IOException
* if an error occurred reading the data
*/
static String scanPublicID(StringBuffer publicID,
StdXMLReader reader)
throws IOException,
XMLParseException
{
if (! XMLUtil.checkLiteral(reader, "UBLIC")) {
return null;
}
XMLUtil.skipWhitespace(reader, null);
publicID.append(XMLUtil.scanString(reader, '\0', null));
XMLUtil.skipWhitespace(reader, null);
return XMLUtil.scanString(reader, '\0', null);
}
/**
* Scans a system ID.
*
* @param reader the reader
*
* @return the system ID
*
* @throws java.io.IOException
* if an error occurred reading the data
*/
static String scanSystemID(StdXMLReader reader)
throws IOException,
XMLParseException
{
if (! XMLUtil.checkLiteral(reader, "YSTEM")) {
return null;
}
XMLUtil.skipWhitespace(reader, null);
return XMLUtil.scanString(reader, '\0', null);
}
/**
* Retrieves an identifier from the data.
*
* @param reader the reader
*
* @throws java.io.IOException
* if an error occurred reading the data
*/
static String scanIdentifier(StdXMLReader reader)
throws IOException,
XMLParseException
{
StringBuffer result = new StringBuffer();
for (;;) {
char ch = reader.read();
if ((ch == '_') || (ch == ':') || (ch == '-') || (ch == '.')
|| ((ch >= 'a') && (ch <= 'z'))
|| ((ch >= 'A') && (ch <= 'Z'))
|| ((ch >= '0') && (ch <= '9')) || (ch > '\u007E')) {
result.append(ch);
} else {
reader.unread(ch);
break;
}
}
return result.toString();
}
/**
* Retrieves a delimited string from the data.
*
* @param reader the reader
* @param entityChar the escape character (&amp; or %)
* @param entityResolver the entity resolver
*
* @throws java.io.IOException
* if an error occurred reading the data
*/
static String scanString(StdXMLReader reader,
char entityChar,
XMLEntityResolver entityResolver)
throws IOException,
XMLParseException
{
StringBuffer result = new StringBuffer();
int startingLevel = reader.getStreamLevel();
char delim = reader.read();
if ((delim != '\'') && (delim != '"')) {
XMLUtil.errorExpectedInput(reader.getSystemID(),
reader.getLineNr(),
"delimited string");
}
for (;;) {
String str = XMLUtil.read(reader, entityChar);
char ch = str.charAt(0);
if (ch == entityChar) {
if (str.charAt(1) == '#') {
result.append(XMLUtil.processCharLiteral(str));
} else {
XMLUtil.processEntity(str, reader, entityResolver);
}
} else if (ch == '&') {
reader.unread(ch);
str = XMLUtil.read(reader, '&');
if (str.charAt(1) == '#') {
result.append(XMLUtil.processCharLiteral(str));
} else {
result.append(str);
}
} else if (reader.getStreamLevel() == startingLevel) {
if (ch == delim) {
break;
} else if ((ch == 9) || (ch == 10) || (ch == 13)) {
result.append(' ');
} else {
result.append(ch);
}
} else {
result.append(ch);
}
}
return result.toString();
}
/**
* Processes an entity.
*
* @param entity the entity
* @param reader the reader
* @param entityResolver the entity resolver
*
* @throws java.io.IOException
* if an error occurred reading the data
*/
static void processEntity(String entity,
StdXMLReader reader,
XMLEntityResolver entityResolver)
throws IOException,
XMLParseException
{
entity = entity.substring(1, entity.length() - 1);
Reader entityReader = entityResolver.getEntity(reader, entity);
if (entityReader == null) {
XMLUtil.errorInvalidEntity(reader.getSystemID(),
reader.getLineNr(),
entity);
}
boolean externalEntity = entityResolver.isExternalEntity(entity);
reader.startNewStream(entityReader, !externalEntity);
}
/**
* Processes a character literal.
*
* @param entity the entity
*
* @throws java.io.IOException
* if an error occurred reading the data
*/
static char processCharLiteral(String entity)
throws IOException,
XMLParseException
{
if (entity.charAt(2) == 'x') {
entity = entity.substring(3, entity.length() - 1);
return (char) Integer.parseInt(entity, 16);
} else {
entity = entity.substring(2, entity.length() - 1);
return (char) Integer.parseInt(entity, 10);
}
}
/**
* Skips whitespace from the reader.
*
* @param reader the reader
* @param buffer where to put the whitespace; null if the
* whitespace does not have to be stored.
*
* @throws java.io.IOException
* if an error occurred reading the data
*/
static void skipWhitespace(StdXMLReader reader,
StringBuffer buffer)
throws IOException
{
char ch;
if (buffer == null) {
do {
ch = reader.read();
} while ((ch == ' ') || (ch == '\t') || (ch == '\n'));
} else {
for (;;) {
ch = reader.read();
if ((ch != ' ') && (ch != '\t') && (ch != '\n')) {
break;
}
if (ch == '\n') {
buffer.append('\n');
} else {
buffer.append(' ');
}
}
}
reader.unread(ch);
}
/**
* Reads a character from the reader.
*
* @param reader the reader
* @param entityChar the escape character (&amp; or %) used to indicate
* an entity
*
* @return the character, or an entity expression (like e.g. &amp;lt;)
*
* @throws java.io.IOException
* if an error occurred reading the data
*/
static String read(StdXMLReader reader,
char entityChar) throws IOException, XMLParseException {
char ch = reader.read();
StringBuffer buf = new StringBuffer();
buf.append(ch);
if (ch == entityChar) {
while (ch != ';') {
ch = reader.read();
buf.append(ch);
}
}
return buf.toString();
}
/**
* Reads a character from the reader disallowing entities.
*
* @param reader the reader
* @param entityChar the escape character (&amp; or %) used to indicate
* an entity
*/
static char readChar(StdXMLReader reader,
char entityChar) throws IOException, XMLParseException {
String str = XMLUtil.read(reader, entityChar);
char ch = str.charAt(0);
if (ch == entityChar) {
XMLUtil.errorUnexpectedEntity(reader.getSystemID(),
reader.getLineNr(),
str);
}
return ch;
}
/**
* Returns true if the data starts with <I>literal</I>.
* Enough chars are read to determine this result.
*
* @param reader the reader
* @param literal the literal to check
*
* @throws java.io.IOException
* if an error occurred reading the data
*/
static boolean checkLiteral(StdXMLReader reader,
String literal)
throws IOException,
XMLParseException
{
for (int i = 0; i < literal.length(); i++) {
if (reader.read() != literal.charAt(i)) {
return false;
}
}
return true;
}
/**
* Throws an XMLParseException to indicate that an expected string is not
* encountered.
*
* @param systemID the system ID of the data source
* @param lineNr the line number in the data source
* @param expectedString the string that is expected
*/
static void errorExpectedInput(String systemID,
int lineNr,
String expectedString)
throws XMLParseException
{
throw new XMLParseException(systemID, lineNr,
"Expected: " + expectedString);
}
/**
* Throws an XMLParseException to indicate that an entity could not be
* resolved.
*
* @param systemID the system ID of the data source
* @param lineNr the line number in the data source
* @param entity the name of the entity
*/
static void errorInvalidEntity(String systemID,
int lineNr,
String entity)
throws XMLParseException
{
throw new XMLParseException(systemID, lineNr,
"Invalid entity: `&" + entity + ";'");
}
/**
* Throws an XMLParseException to indicate that an entity reference is
* unexpected at this point.
*
* @param systemID the system ID of the data source
* @param lineNr the line number in the data source
* @param entity the name of the entity
*/
static void errorUnexpectedEntity(String systemID,
int lineNr,
String entity)
throws XMLParseException
{
throw new XMLParseException(systemID, lineNr,
"No entity reference is expected here ("
+ entity + ")");
}
/**
* Throws an XMLParseException to indicate that a CDATA section is
* unexpected at this point.
*
* @param systemID the system ID of the data source
* @param lineNr the line number in the data source
*/
static void errorUnexpectedCDATA(String systemID,
int lineNr)
throws XMLParseException
{
throw new XMLParseException(systemID, lineNr,
"No CDATA section is expected here");
}
/**
* Throws an XMLParseException to indicate that a string is not expected
* at this point.
*
* @param systemID the system ID of the data source
* @param lineNr the line number in the data source
* @param unexpectedString the string that is unexpected
*/
static void errorInvalidInput(String systemID,
int lineNr,
String unexpectedString)
throws XMLParseException
{
throw new XMLParseException(systemID, lineNr,
"Invalid input: " + unexpectedString);
}
/**
* Throws an XMLParseException to indicate that the closing tag of an
* element does not match the opening tag.
*
* @param systemID the system ID of the data source
* @param lineNr the line number in the data source
* @param expectedName the name of the opening tag
* @param wrongName the name of the closing tag
*/
static void errorWrongClosingTag(String systemID,
int lineNr,
String expectedName,
String wrongName)
throws XMLParseException
{
throw new XMLParseException(systemID, lineNr,
"Closing tag does not match opening tag: `"
+ wrongName + "' != `" + expectedName
+ "'");
}
/**
* Throws an XMLParseException to indicate that extra data is encountered
* in a closing tag.
*
* @param systemID the system ID of the data source
* @param lineNr the line number in the data source
*/
static void errorClosingTagNotEmpty(String systemID,
int lineNr)
throws XMLParseException
{
throw new XMLParseException(systemID, lineNr,
"Closing tag must be empty");
}
/**
* Throws an XMLValidationException to indicate that an element is missing.
*
* @param systemID the system ID of the data source
* @param lineNr the line number in the data source
* @param parentElementName the name of the parent element
* @param missingElementName the name of the missing element
*/
static void errorMissingElement(String systemID,
int lineNr,
String parentElementName,
String missingElementName)
throws XMLValidationException
{
throw new XMLValidationException(
XMLValidationException.MISSING_ELEMENT,
systemID, lineNr,
missingElementName,
/*attributeName*/ null,
/*attributeValue*/ null,
"Element " + parentElementName
+ " expects to have a " + missingElementName);
}
/**
* Throws an XMLValidationException to indicate that an element is
* unexpected.
*
* @param systemID the system ID of the data source
* @param lineNr the line number in the data source
* @param parentElementName the name of the parent element
* @param unexpectedElementName the name of the unexpected element
*/
static void errorUnexpectedElement(String systemID,
int lineNr,
String parentElementName,
String unexpectedElementName)
throws XMLValidationException
{
throw new XMLValidationException(
XMLValidationException.UNEXPECTED_ELEMENT,
systemID, lineNr,
unexpectedElementName,
/*attributeName*/ null,
/*attributeValue*/ null,
"Unexpected " + unexpectedElementName + " in a "
+ parentElementName);
}
/**
* Throws an XMLValidationException to indicate that an attribute is
* missing.
*
* @param systemID the system ID of the data source
* @param lineNr the line number in the data source
* @param elementName the name of the element
* @param attributeName the name of the missing attribute
*/
static void errorMissingAttribute(String systemID,
int lineNr,
String elementName,
String attributeName)
throws XMLValidationException
{
throw new XMLValidationException(
XMLValidationException.MISSING_ATTRIBUTE,
systemID, lineNr,
elementName,
attributeName,
/*attributeValue*/ null,
"Element " + elementName + " expects an attribute named "
+ attributeName);
}
/**
* Throws an XMLValidationException to indicate that an attribute is
* unexpected.
*
* @param systemID the system ID of the data source
* @param lineNr the line number in the data source
* @param elementName the name of the element
* @param attributeName the name of the unexpected attribute
*/
static void errorUnexpectedAttribute(String systemID,
int lineNr,
String elementName,
String attributeName)
throws XMLValidationException
{
throw new XMLValidationException(
XMLValidationException.UNEXPECTED_ATTRIBUTE,
systemID, lineNr,
elementName,
attributeName,
/*attributeValue*/ null,
"Element " + elementName + " did not expect an attribute "
+ "named " + attributeName);
}
/**
* Throws an XMLValidationException to indicate that an attribute has an
* invalid value.
*
* @param systemID the system ID of the data source
* @param lineNr the line number in the data source
* @param elementName the name of the element
* @param attributeName the name of the attribute
* @param attributeValue the value of that attribute
*/
static void errorInvalidAttributeValue(String systemID,
int lineNr,
String elementName,
String attributeName,
String attributeValue)
throws XMLValidationException
{
throw new XMLValidationException(
XMLValidationException.ATTRIBUTE_WITH_INVALID_VALUE,
systemID, lineNr,
elementName,
attributeName,
attributeValue,
"Invalid value for attribute " + attributeName);
}
/**
* Throws an XMLValidationException to indicate that a #PCDATA element was
* missing.
*
* @param systemID the system ID of the data source
* @param lineNr the line number in the data source
* @param parentElementName the name of the parent element
*/
static void errorMissingPCData(String systemID,
int lineNr,
String parentElementName)
throws XMLValidationException
{
throw new XMLValidationException(
XMLValidationException.MISSING_PCDATA,
systemID, lineNr,
/*elementName*/ null,
/*attributeName*/ null,
/*attributeValue*/ null,
"Missing #PCDATA in element " + parentElementName);
}
/**
* Throws an XMLValidationException to indicate that a #PCDATA element was
* unexpected.
*
* @param systemID the system ID of the data source
* @param lineNr the line number in the data source
* @param parentElementName the name of the parent element
*/
static void errorUnexpectedPCData(String systemID,
int lineNr,
String parentElementName)
throws XMLValidationException
{
throw new XMLValidationException(
XMLValidationException.UNEXPECTED_PCDATA,
systemID, lineNr,
/*elementName*/ null,
/*attributeName*/ null,
/*attributeValue*/ null,
"Unexpected #PCDATA in element " + parentElementName);
}
/**
* Throws an XMLValidationException.
*
* @param systemID the system ID of the data source
* @param lineNr the line number in the data source
* @param message the error message
* @param elementName the name of the element
* @param attributeName the name of the attribute
* @param attributeValue the value of that attribute
*/
static void validationError(String systemID,
int lineNr,
String message,
String elementName,
String attributeName,
String attributeValue)
throws XMLValidationException
{
throw new XMLValidationException(XMLValidationException.MISC_ERROR,
systemID, lineNr,
elementName,
attributeName,
attributeValue,
message);
}
}
@@ -0,0 +1,190 @@
/* XMLValidationException.java NanoXML/Java
*
* $Revision: 1.3 $
* $Date: 2002/01/04 21:03:29 $
* $Name: RELEASE_2_2_1 $
*
* This file is part of NanoXML 2 for Java.
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the
* use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
package processing.xml;
/**
* An XMLValidationException is thrown when the XML passed to the XML parser is
* well-formed but not valid.
*
* @author Marc De Scheemaecker
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.3 $
*/
public class XMLValidationException
extends XMLException
{
/**
* An element was missing.
*/
public static final int MISSING_ELEMENT = 1;
/**
* An unexpected element was encountered.
*/
public static final int UNEXPECTED_ELEMENT = 2;
/**
* An attribute was missing.
*/
public static final int MISSING_ATTRIBUTE = 3;
/**
* An unexpected attribute was encountered.
*/
public static final int UNEXPECTED_ATTRIBUTE = 4;
/**
* An attribute has an invalid value.
*/
public static final int ATTRIBUTE_WITH_INVALID_VALUE = 5;
/**
* A PCDATA element was missing.
*/
public static final int MISSING_PCDATA = 6;
/**
* An unexpected PCDATA element was encountered.
*/
public static final int UNEXPECTED_PCDATA = 7;
/**
* Another error than those specified in this class was encountered.
*/
public static final int MISC_ERROR = 0;
/**
* Which error occurred.
*/
//private int errorType;
/**
* The name of the element where the exception occurred.
*/
private String elementName;
/**
* The name of the attribute where the exception occurred.
*/
private String attributeName;
/**
* The value of the attribute where the exception occurred.
*/
private String attributeValue;
/**
* Creates a new exception.
*
* @param errorType the type of validity error
* @param systemID the system ID from where the data came
* @param lineNr the line number in the XML data where the
* exception occurred.
* @param elementName the name of the offending element
* @param attributeName the name of the offending attribute
* @param attributeValue the value of the offending attribute
* @param msg the message of the exception.
*/
public XMLValidationException(int errorType,
String systemID,
int lineNr,
String elementName,
String attributeName,
String attributeValue,
String msg)
{
super(systemID, lineNr, null,
msg + ((elementName == null) ? "" : (", element=" + elementName))
+ ((attributeName == null) ? ""
: (", attribute=" + attributeName))
+ ((attributeValue == null) ? ""
: (", value='" + attributeValue + "'")),
false);
this.elementName = elementName;
this.attributeName = attributeName;
this.attributeValue = attributeValue;
}
/**
* Cleans up the object when it's destroyed.
*/
protected void finalize()
throws Throwable
{
this.elementName = null;
this.attributeName = null;
this.attributeValue = null;
super.finalize();
}
/**
* Returns the name of the element in which the validation is violated.
* If there is no current element, null is returned.
*/
public String getElementName()
{
return this.elementName;
}
/**
* Returns the name of the attribute in which the validation is violated.
* If there is no current attribute, null is returned.
*/
public String getAttributeName()
{
return this.attributeName;
}
/**
* Returns the value of the attribute in which the validation is violated.
* If there is no current attribute, null is returned.
*/
public String getAttributeValue()
{
return this.attributeValue;
}
}
+631
View File
@@ -0,0 +1,631 @@
/* NonValidator.java NanoXML/Java
*
* $Revision: 1.4 $
* $Date: 2002/02/03 21:19:38 $
* $Name: RELEASE_2_2_1 $
*
* This file is part of NanoXML 2 for Java.
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the
* use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
package processing.xml;
import java.io.Reader;
import java.io.StringReader;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Stack;
/**
* XMLValidator implementation based on NonValidator (which implemented
* IXMLValidator in the original NanoXML).
* This implementation processes the DTD and handles entity definitions.
* It does not do any validation itself.
*
* @author Marc De Scheemaecker
* @author processing.org
*/
public class XMLValidator
{
/**
* The parameter entity resolver.
*/
protected XMLEntityResolver parameterEntityResolver;
/**
* Contains the default values for attributes for the different element
* types.
*/
protected Hashtable attributeDefaultValues;
/**
* The stack of elements to be processed.
*/
protected Stack currentElements;
/**
* Creates the &quot;validator&quot;.
*/
public XMLValidator()
{
this.attributeDefaultValues = new Hashtable();
this.currentElements = new Stack();
this.parameterEntityResolver = new XMLEntityResolver();
}
/**
* Cleans up the object when it's destroyed.
*/
protected void finalize()
throws Throwable
{
this.parameterEntityResolver = null;
this.attributeDefaultValues.clear();
this.attributeDefaultValues = null;
this.currentElements.clear();
this.currentElements = null;
super.finalize();
}
/**
* Sets the parameter entity resolver.
*
* @param resolver the entity resolver.
*/
public void setParameterEntityResolver(XMLEntityResolver resolver)
{
this.parameterEntityResolver = resolver;
}
/**
* Returns the parameter entity resolver.
*
* @return the entity resolver.
*/
public XMLEntityResolver getParameterEntityResolver()
{
return this.parameterEntityResolver;
}
/**
* Parses the DTD. The validator object is responsible for reading the
* full DTD.
*
* @param publicID the public ID, which may be null.
* @param reader the reader to read the DTD from.
* @param entityResolver the entity resolver.
* @param external true if the DTD is external.
*
* @throws java.lang.Exception
* If something went wrong.
*/
public void parseDTD(String publicID,
StdXMLReader reader,
XMLEntityResolver entityResolver,
boolean external)
throws Exception
{
XMLUtil.skipWhitespace(reader, null);
int origLevel = reader.getStreamLevel();
for (;;) {
String str = XMLUtil.read(reader, '%');
char ch = str.charAt(0);
if (ch == '%') {
XMLUtil.processEntity(str, reader,
this.parameterEntityResolver);
continue;
} else if (ch == '<') {
this.processElement(reader, entityResolver);
} else if (ch == ']') {
return; // end internal DTD
} else {
XMLUtil.errorInvalidInput(reader.getSystemID(),
reader.getLineNr(),
str);
}
do {
ch = reader.read();
if (external && (reader.getStreamLevel() < origLevel)) {
reader.unread(ch);
return; // end external DTD
}
} while ((ch == ' ') || (ch == '\t') || (ch == '\n')
|| (ch == '\r'));
reader.unread(ch);
}
}
/**
* Processes an element in the DTD.
*
* @param reader the reader to read data from.
* @param entityResolver the entity resolver.
*
* @throws java.lang.Exception
* If something went wrong.
*/
protected void processElement(StdXMLReader reader,
XMLEntityResolver entityResolver)
throws Exception
{
String str = XMLUtil.read(reader, '%');
char ch = str.charAt(0);
if (ch != '!') {
XMLUtil.skipTag(reader);
return;
}
str = XMLUtil.read(reader, '%');
ch = str.charAt(0);
switch (ch) {
case '-':
XMLUtil.skipComment(reader);
break;
case '[':
this.processConditionalSection(reader, entityResolver);
break;
case 'E':
this.processEntity(reader, entityResolver);
break;
case 'A':
this.processAttList(reader, entityResolver);
break;
default:
XMLUtil.skipTag(reader);
}
}
/**
* Processes a conditional section.
*
* @param reader the reader to read data from.
* @param entityResolver the entity resolver.
*
* @throws java.lang.Exception
* If something went wrong.
*/
protected void processConditionalSection(StdXMLReader reader,
XMLEntityResolver entityResolver)
throws Exception
{
XMLUtil.skipWhitespace(reader, null);
String str = XMLUtil.read(reader, '%');
char ch = str.charAt(0);
if (ch != 'I') {
XMLUtil.skipTag(reader);
return;
}
str = XMLUtil.read(reader, '%');
ch = str.charAt(0);
switch (ch) {
case 'G':
this.processIgnoreSection(reader, entityResolver);
return;
case 'N':
break;
default:
XMLUtil.skipTag(reader);
return;
}
if (! XMLUtil.checkLiteral(reader, "CLUDE")) {
XMLUtil.skipTag(reader);
return;
}
XMLUtil.skipWhitespace(reader, null);
str = XMLUtil.read(reader, '%');
ch = str.charAt(0);
if (ch != '[') {
XMLUtil.skipTag(reader);
return;
}
Reader subreader = new CDATAReader(reader);
StringBuffer buf = new StringBuffer(1024);
for (;;) {
int ch2 = subreader.read();
if (ch2 < 0) {
break;
}
buf.append((char) ch2);
}
subreader.close();
reader.startNewStream(new StringReader(buf.toString()));
}
/**
* Processes an ignore section.
*
* @param reader the reader to read data from.
* @param entityResolver the entity resolver.
*
* @throws java.lang.Exception
* If something went wrong.
*/
protected void processIgnoreSection(StdXMLReader reader,
XMLEntityResolver entityResolver)
throws Exception
{
if (! XMLUtil.checkLiteral(reader, "NORE")) {
XMLUtil.skipTag(reader);
return;
}
XMLUtil.skipWhitespace(reader, null);
String str = XMLUtil.read(reader, '%');
char ch = str.charAt(0);
if (ch != '[') {
XMLUtil.skipTag(reader);
return;
}
Reader subreader = new CDATAReader(reader);
subreader.close();
}
/**
* Processes an ATTLIST element.
*
* @param reader the reader to read data from.
* @param entityResolver the entity resolver.
*
* @throws java.lang.Exception
* If something went wrong.
*/
protected void processAttList(StdXMLReader reader,
XMLEntityResolver entityResolver)
throws Exception
{
if (! XMLUtil.checkLiteral(reader, "TTLIST")) {
XMLUtil.skipTag(reader);
return;
}
XMLUtil.skipWhitespace(reader, null);
String str = XMLUtil.read(reader, '%');
char ch = str.charAt(0);
while (ch == '%') {
XMLUtil.processEntity(str, reader,
this.parameterEntityResolver);
str = XMLUtil.read(reader, '%');
ch = str.charAt(0);
}
reader.unread(ch);
String elementName = XMLUtil.scanIdentifier(reader);
XMLUtil.skipWhitespace(reader, null);
str = XMLUtil.read(reader, '%');
ch = str.charAt(0);
while (ch == '%') {
XMLUtil.processEntity(str, reader,
this.parameterEntityResolver);
str = XMLUtil.read(reader, '%');
ch = str.charAt(0);
}
Properties props = new Properties();
while (ch != '>') {
reader.unread(ch);
String attName = XMLUtil.scanIdentifier(reader);
XMLUtil.skipWhitespace(reader, null);
str = XMLUtil.read(reader, '%');
ch = str.charAt(0);
while (ch == '%') {
XMLUtil.processEntity(str, reader,
this.parameterEntityResolver);
str = XMLUtil.read(reader, '%');
ch = str.charAt(0);
}
if (ch == '(') {
while (ch != ')') {
str = XMLUtil.read(reader, '%');
ch = str.charAt(0);
while (ch == '%') {
XMLUtil.processEntity(str, reader,
this.parameterEntityResolver);
str = XMLUtil.read(reader, '%');
ch = str.charAt(0);
}
}
} else {
reader.unread(ch);
XMLUtil.scanIdentifier(reader);
}
XMLUtil.skipWhitespace(reader, null);
str = XMLUtil.read(reader, '%');
ch = str.charAt(0);
while (ch == '%') {
XMLUtil.processEntity(str, reader,
this.parameterEntityResolver);
str = XMLUtil.read(reader, '%');
ch = str.charAt(0);
}
if (ch == '#') {
str = XMLUtil.scanIdentifier(reader);
XMLUtil.skipWhitespace(reader, null);
if (! str.equals("FIXED")) {
XMLUtil.skipWhitespace(reader, null);
str = XMLUtil.read(reader, '%');
ch = str.charAt(0);
while (ch == '%') {
XMLUtil.processEntity(str, reader,
this.parameterEntityResolver);
str = XMLUtil.read(reader, '%');
ch = str.charAt(0);
}
continue;
}
} else {
reader.unread(ch);
}
String value = XMLUtil.scanString(reader, '%',
this.parameterEntityResolver);
props.put(attName, value);
XMLUtil.skipWhitespace(reader, null);
str = XMLUtil.read(reader, '%');
ch = str.charAt(0);
while (ch == '%') {
XMLUtil.processEntity(str, reader,
this.parameterEntityResolver);
str = XMLUtil.read(reader, '%');
ch = str.charAt(0);
}
}
if (! props.isEmpty()) {
this.attributeDefaultValues.put(elementName, props);
}
}
/**
* Processes an ENTITY element.
*
* @param reader the reader to read data from.
* @param entityResolver the entity resolver.
*
* @throws java.lang.Exception
* If something went wrong.
*/
protected void processEntity(StdXMLReader reader,
XMLEntityResolver entityResolver)
throws Exception
{
if (! XMLUtil.checkLiteral(reader, "NTITY")) {
XMLUtil.skipTag(reader);
return;
}
XMLUtil.skipWhitespace(reader, null);
char ch = XMLUtil.readChar(reader, '\0');
if (ch == '%') {
XMLUtil.skipWhitespace(reader, null);
entityResolver = this.parameterEntityResolver;
} else {
reader.unread(ch);
}
String key = XMLUtil.scanIdentifier(reader);
XMLUtil.skipWhitespace(reader, null);
ch = XMLUtil.readChar(reader, '%');
String systemID = null;
String publicID = null;
switch (ch) {
case 'P':
if (! XMLUtil.checkLiteral(reader, "UBLIC")) {
XMLUtil.skipTag(reader);
return;
}
XMLUtil.skipWhitespace(reader, null);
publicID = XMLUtil.scanString(reader, '%',
this.parameterEntityResolver);
XMLUtil.skipWhitespace(reader, null);
systemID = XMLUtil.scanString(reader, '%',
this.parameterEntityResolver);
XMLUtil.skipWhitespace(reader, null);
XMLUtil.readChar(reader, '%');
break;
case 'S':
if (! XMLUtil.checkLiteral(reader, "YSTEM")) {
XMLUtil.skipTag(reader);
return;
}
XMLUtil.skipWhitespace(reader, null);
systemID = XMLUtil.scanString(reader, '%',
this.parameterEntityResolver);
XMLUtil.skipWhitespace(reader, null);
XMLUtil.readChar(reader, '%');
break;
case '"':
case '\'':
reader.unread(ch);
String value = XMLUtil.scanString(reader, '%',
this.parameterEntityResolver);
entityResolver.addInternalEntity(key, value);
XMLUtil.skipWhitespace(reader, null);
XMLUtil.readChar(reader, '%');
break;
default:
XMLUtil.skipTag(reader);
}
if (systemID != null) {
entityResolver.addExternalEntity(key, publicID, systemID);
}
}
/**
* Indicates that an element has been started.
*
* @param name the name of the element.
* @param systemId the system ID of the XML data of the element.
* @param lineNr the line number in the XML data of the element.
*/
public void elementStarted(String name,
String systemId,
int lineNr)
{
Properties attribs
= (Properties) this.attributeDefaultValues.get(name);
if (attribs == null) {
attribs = new Properties();
} else {
attribs = (Properties) attribs.clone();
}
this.currentElements.push(attribs);
}
/**
* Indicates that the current element has ended.
*
* @param name the name of the element.
* @param systemId the system ID of the XML data of the element.
* @param lineNr the line number in the XML data of the element.
*/
public void elementEnded(String name,
String systemId,
int lineNr)
{
// nothing to do
}
/**
* This method is called when the attributes of an XML element have been
* processed.
* If there are attributes with a default value which have not been
* specified yet, they have to be put into <I>extraAttributes</I>.
*
* @param name the name of the element.
* @param extraAttributes where to put extra attributes.
* @param systemId the system ID of the XML data of the element.
* @param lineNr the line number in the XML data of the element.
*/
public void elementAttributesProcessed(String name,
Properties extraAttributes,
String systemId,
int lineNr)
{
Properties props = (Properties) this.currentElements.pop();
Enumeration en = props.keys();
while (en.hasMoreElements()) {
String key = (String) en.nextElement();
extraAttributes.put(key, props.get(key));
}
}
/**
* Indicates that an attribute has been added to the current element.
*
* @param key the name of the attribute.
* @param value the value of the attribute.
* @param systemId the system ID of the XML data of the element.
* @param lineNr the line number in the XML data of the element.
*/
public void attributeAdded(String key,
String value,
String systemId,
int lineNr)
{
Properties props = (Properties) this.currentElements.peek();
if (props.containsKey(key)) {
props.remove(key);
}
}
/**
* Indicates that a new #PCDATA element has been encountered.
*
* @param systemId the system ID of the XML data of the element.
* @param lineNr the line number in the XML data of the element.
*/
public void PCDataAdded(String systemId,
int lineNr)
{
// nothing to do
}
}
+311
View File
@@ -0,0 +1,311 @@
/* XMLWriter.java NanoXML/Java
*
* $Revision: 1.4 $
* $Date: 2002/03/24 11:37:51 $
* $Name: RELEASE_2_2_1 $
*
* This file is part of NanoXML 2 for Java.
* Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the
* use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
package processing.xml;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Enumeration;
import java.util.Vector;
/**
* An XMLWriter writes XML data to a stream.
*
* @see net.n3.nanoxml.IXMLElement
* @see java.io.Writer
*
* @author Marc De Scheemaecker
* @version $Name: RELEASE_2_2_1 $, $Revision: 1.4 $
*/
public class XMLWriter
{
/**
* Where to write the output to.
*/
private PrintWriter writer;
/**
* Creates a new XML writer.
*
* @param writer where to write the output to.
*/
public XMLWriter(Writer writer)
{
if (writer instanceof PrintWriter) {
this.writer = (PrintWriter) writer;
} else {
this.writer = new PrintWriter(writer);
}
}
/**
* Creates a new XML writer.
*
* @param stream where to write the output to.
*/
public XMLWriter(OutputStream stream)
{
this.writer = new PrintWriter(stream);
}
/**
* Cleans up the object when it's destroyed.
*/
protected void finalize()
throws Throwable
{
this.writer = null;
super.finalize();
}
/**
* Writes an XML element.
*
* @param xml the non-null XML element to write.
*/
public void write(XMLElement xml)
throws IOException
{
this.write(xml, false, 0, true);
}
/**
* Writes an XML element.
*
* @param xml the non-null XML element to write.
* @param prettyPrint if spaces need to be inserted to make the output more
* readable
*/
public void write(XMLElement xml,
boolean prettyPrint)
throws IOException
{
this.write(xml, prettyPrint, 0, true);
}
/**
* Writes an XML element.
*
* @param xml the non-null XML element to write.
* @param prettyPrint if spaces need to be inserted to make the output more
* readable
* @param indent how many spaces to indent the element.
*/
public void write(XMLElement xml,
boolean prettyPrint,
int indent)
throws IOException
{
this.write(xml, prettyPrint, indent, true);
}
/**
* Writes an XML element.
*
* @param xml the non-null XML element to write.
* @param prettyPrint if spaces need to be inserted to make the output more
* readable
* @param indent how many spaces to indent the element.
*/
public void write(XMLElement xml,
boolean prettyPrint,
int indent,
boolean collapseEmptyElements)
throws IOException
{
if (prettyPrint) {
for (int i = 0; i < indent; i++) {
this.writer.print(' ');
}
}
if (xml.getName() == null) {
if (xml.getContent() != null) {
if (prettyPrint) {
this.writeEncoded(xml.getContent().trim());
writer.println();
} else {
this.writeEncoded(xml.getContent());
}
}
} else {
this.writer.print('<');
this.writer.print(xml.getFullName());
Vector nsprefixes = new Vector();
if (xml.getNamespace() != null) {
if (xml.getName().equals(xml.getFullName())) {
this.writer.print(" xmlns=\"" + xml.getNamespace() + '"');
} else {
String prefix = xml.getFullName();
prefix = prefix.substring(0, prefix.indexOf(':'));
nsprefixes.addElement(prefix);
this.writer.print(" xmlns:" + prefix);
this.writer.print("=\"" + xml.getNamespace() + "\"");
}
}
Enumeration en = xml.enumerateAttributeNames();
while (en.hasMoreElements()) {
String key = (String) en.nextElement();
int index = key.indexOf(':');
if (index >= 0) {
String namespace = xml.getAttributeNamespace(key);
if (namespace != null) {
String prefix = key.substring(0, index);
if (! nsprefixes.contains(prefix)) {
this.writer.print(" xmlns:" + prefix);
this.writer.print("=\"" + namespace + '"');
nsprefixes.addElement(prefix);
}
}
}
}
en = xml.enumerateAttributeNames();
while (en.hasMoreElements()) {
String key = (String) en.nextElement();
String value = xml.getAttribute(key, null);
this.writer.print(" " + key + "=\"");
this.writeEncoded(value);
this.writer.print('"');
}
if ((xml.getContent() != null)
&& (xml.getContent().length() > 0)) {
writer.print('>');
this.writeEncoded(xml.getContent());
writer.print("</" + xml.getFullName() + '>');
if (prettyPrint) {
writer.println();
}
} else if (xml.hasChildren() || (! collapseEmptyElements)) {
writer.print('>');
if (prettyPrint) {
writer.println();
}
en = xml.enumerateChildren();
while (en.hasMoreElements()) {
XMLElement child = (XMLElement) en.nextElement();
this.write(child, prettyPrint, indent + 4,
collapseEmptyElements);
}
if (prettyPrint) {
for (int i = 0; i < indent; i++) {
this.writer.print(' ');
}
}
this.writer.print("</" + xml.getFullName() + ">");
if (prettyPrint) {
writer.println();
}
} else {
this.writer.print("/>");
if (prettyPrint) {
writer.println();
}
}
}
this.writer.flush();
}
/**
* Writes a string encoding reserved characters.
*
* @param str the string to write.
*/
private void writeEncoded(String str)
{
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
switch (c) {
case 0x0A:
this.writer.print(c);
break;
case '<':
this.writer.print("&lt;");
break;
case '>':
this.writer.print("&gt;");
break;
case '&':
this.writer.print("&amp;");
break;
case '\'':
this.writer.print("&apos;");
break;
case '"':
this.writer.print("&quot;");
break;
default:
if ((c < ' ') || (c > 0x7E)) {
this.writer.print("&#x");
this.writer.print(Integer.toString(c, 16));
this.writer.print(';');
} else {
this.writer.print(c);
}
}
}
}
}