📄 xmlparser.java
字号:
loop: while (c != delim) {
switch (c) {
// Literals never have line ends
case '\n':
case '\r':
c = ' ';
break;
// References may be allowed
case '&':
if ((flags & LIT_CHAR_REF) > 0) {
c = readCh();
if (c == '#') {
parseCharRef();
c = readCh();
continue loop; // check the next character
} else if ((flags & LIT_ENTITY_REF) > 0) {
unread(c);
parseEntityRef(false);
c = readCh();
continue loop;
} else {
dataBufferAppend('&');
}
}
break;
default:
break;
}
dataBufferAppend(c);
c = readCh();
}
} catch (EOFException e) {
error("end of input while looking for delimiter (started on line "
+ startLine + ')', null, new Character(delim).toString());
}
// Normalise whitespace if necessary.
if ((flags & LIT_NORMALIZE) > 0) {
dataBufferNormalize();
}
// Return the value.
return dataBufferToString();
}
/**
* Try reading external identifiers.
* <p>The system identifier is not required for notations.
* @param inNotation Are we in a notation?
* @return A two-member String array containing the identifiers.
*/
String[] readExternalIds (boolean inNotation)
throws java.lang.Exception
{
char c;
String ids[] = new String[2];
if (tryRead("PUBLIC")) {
requireWhitespace();
ids[0] = readLiteral(LIT_NORMALIZE); // public id
if (inNotation) {
skipWhitespace();
if (tryRead('"') || tryRead('\'')) {
ids[1] = readLiteral(0);
}
} else {
requireWhitespace();
ids[1] = readLiteral(0); // system id
}
} else if (tryRead("SYSTEM")) {
requireWhitespace();
ids[1] = readLiteral(0); // system id
}
return ids;
}
/**
* Test if a character is whitespace.
* <pre>
* [1] S ::= (#x20 | #x9 | #xd | #xa)+
* </pre>
* @param c The character to test.
* @return true if the character is whitespace.
*/
final boolean isWhitespace (char c)
{
switch ((int)c) {
case 0x20:
case 0x09:
case 0x0d:
case 0x0a:
return true;
default:
return false;
}
}
//////////////////////////////////////////////////////////////////////
// Utility routines.
//////////////////////////////////////////////////////////////////////
/**
* Add a character to the data buffer.
*/
void dataBufferAppend (char c)
{
// Expand buffer if necessary.
dataBuffer =
(char[])extendArray(dataBuffer, dataBuffer.length, dataBufferPos);
dataBuffer[dataBufferPos++] = c;
}
/**
* Add a string to the data buffer.
*/
void dataBufferAppend (String s)
{
dataBufferAppend(s.toCharArray(), 0, s.length());
}
/**
* Append (part of) a character array to the data buffer.
*/
void dataBufferAppend (char ch[], int start, int length)
{
dataBuffer =
(char[])extendArray(dataBuffer, dataBuffer.length,
dataBufferPos + length);
System.arraycopy((Object)ch, start,
(Object)dataBuffer, dataBufferPos,
length);
dataBufferPos += length;
}
/**
* Normalise whitespace in the data buffer.
*/
void dataBufferNormalize ()
{
int i = 0;
int j = 0;
int end = dataBufferPos;
// Skip whitespace at the start.
while (j < end && isWhitespace(dataBuffer[j])) {
j++;
}
// Skip whitespace at the end.
while (end > j && isWhitespace(dataBuffer[end - 1])) {
end --;
}
// Start copying to the left.
while (j < end) {
char c = dataBuffer[j++];
// Normalise all other whitespace to
// a single space.
if (isWhitespace(c)) {
while (j < end && isWhitespace(dataBuffer[j++])) {
}
dataBuffer[i++] = ' ';
dataBuffer[i++] = dataBuffer[j-1];
} else {
dataBuffer[i++] = c;
}
}
// The new length is <= the old one.
dataBufferPos = i;
}
/**
* Convert the data buffer to a string.
* @param internFlag true if the contents should be interned.
* @see #intern(char[],int,int)
*/
String dataBufferToString ()
{
String s = new String(dataBuffer, 0, dataBufferPos);
dataBufferPos = 0;
return s;
}
/**
* Flush the contents of the data buffer to the handler, if
* appropriate, and reset the buffer for new input.
*/
void dataBufferFlush ()
throws java.lang.Exception
{
if (dataBufferPos > 0) {
switch (currentElementContent) {
case CONTENT_UNDECLARED:
case CONTENT_EMPTY:
// do nothing
break;
case CONTENT_MIXED:
case CONTENT_ANY:
if (handler != null) {
handler.charData(dataBuffer, 0, dataBufferPos);
}
break;
case CONTENT_ELEMENTS:
if (handler != null) {
handler.ignorableWhitespace(dataBuffer, 0, dataBufferPos);
}
break;
}
dataBufferPos = 0;
}
}
/**
* Require a string to appear, or throw an exception.
*/
void require (String delim)
throws java.lang.Exception
{
char ch[] = delim.toCharArray();
for (int i = 0; i < ch.length; i++) {
require(ch[i]);
}
}
/**
* Require a character to appear, or throw an exception.
*/
void require (char delim)
throws java.lang.Exception
{
char c = readCh();
if (c != delim) {
error("expected character", c, new Character(delim).toString());
}
}
/**
* Return an internalised version of a string.
* <p>Ælfred uses this method to create an internalised version
* of all names and attribute values, so that it can test equality
* with <code>==</code> instead of <code>String.equals()</code>.
* <p>If you want to be able to test for equality in the same way,
* you can use this method to internalise your own strings first:
* <pre>
* String PARA = handler.intern("PARA");
* </pre>
* <p>Note that this will not return the same results as String.intern().
* @param s The string to internalise.
* @return An internalised version of the string.
* @see #intern(char[],int,int)
* @see java.lang.String#intern
*/
public String intern (String s)
{
char ch[] = s.toCharArray();
return intern(ch, 0, ch.length);
}
/**
* Create an internalised string from a character array.
* <p>This is much more efficient than constructing a non-internalised
* string first, and then internalising it.
* <p>Note that this will not return the same results as String.intern().
* @param ch an array of characters for building the string.
* @param start the starting position in the array.
* @param length the number of characters to place in the string.
* @return an internalised string.
* @see #intern(String)
* @see java.lang.String#intern
*/
public String intern (char ch[], int start, int length)
{
int index;
int hash = 0;
// Generate a hash code.
for (int i = start; i < start + length; i++) {
hash = ((hash << 1) & 0xffffff) + (int)ch[i];
}
hash = hash % SYMBOL_TABLE_LENGTH;
// Get the bucket.
Object bucket[] = (Object[])symbolTable[hash];
if (bucket == null) {
symbolTable[hash] = bucket = new Object[8];
}
// Search for a matching tuple, and
// return the string if we find one.
for (index = 0; index < bucket.length; index += 2) {
char chFound[] = (char[])bucket[index];
// Stop when we hit a null index.
if (chFound == null) {
break;
}
// If they're the same length,
// check for a match.
// If the loop finishes, 'index' will
// contain the current bucket
// position.
if (chFound.length == length) {
for (int i = 0; i < chFound.length; i++) {
// Stop if there are no more tuples.
if (ch[start+i] != chFound[i]) {
break;
} else if (i == length-1) {
// That's it, we have a match!
return (String)bucket[index+1];
}
}
}
}
// Not found -- we'll have to add it.
// Do we have to grow the bucket?
bucket =
(Object[])extendArray(bucket, bucket.length, index);
// OK, add it to the end of the
// bucket.
String s = new String(ch, start, length);
bucket[index] = s.toCharArray();
bucket[index+1] = s;
symbolTable[hash] = bucket;
return s;
}
/**
* Ensure the capacity of an array, allocating a new one if
* necessary.
*/
Object extendArray (Object array, int currentSize, int requiredSize)
{
if (requiredSize < currentSize) {
return array;
} else {
Object newArray = null;
int newSize = currentSize * 2;
if (newSize <= requiredSize) {
newSize = requiredSize + 1;
}
if (array instanceof char[]) {
newArray = new char[currentSize * 2];
} else if (array instanceof Object[]) {
newArray = new Object[currentSize * 2];
}
System.arraycopy(array, 0, newArray, 0, currentSize);
return newArray;
}
}
//////////////////////////////////////////////////////////////////////
// XML query routines.
//////////////////////////////////////////////////////////////////////
//
// Elements
//
/**
* Get the declared elements for an XML document.
* <p>The results will be valid only after the DTD (if any) has been
* parsed.
* @return An enumeration of all element types declared for this
* document (as Strings).
* @see #getElementContentType
* @see #getElementContentModel
*/
public Enumeration declaredElements ()
{
return elementInfo.keys();
}
/**
* Look up the content type of an element.
* @param name The element type name.
* @return An integer constant representing the content type.
* @see #getElementContentModel
* @see #CONTENT_UNDECLARED
* @see #CONTENT_ANY
* @see #CONTENT_EMPTY
* @see #CONTENT_MIXED
* @see #CONTENT_ELEMENTS
*/
public int getElementContentType (String name)
{
Object element[] = (Object[])elementInfo.get(name);
if (element == null) {
return CONTENT_UNDECLARED;
} else {
return ((Integer)element[0]).intValue();
}
}
/**
* Look up the content model of an element.
* <p>The result will always be null unless the content type is
* CONTENT_ELEMENTS or CONTENT_MIXED.
* @param name The element type name.
* @return The normalised content model, as a string.
* @see #getElementContentType
*/
public String getElementContentModel (String name)
{
Object element[] = (Object[])elementInfo.get(name);
if (element == null) {
return null;
} else {
return (String)element[1];
}
}
/**
* Register an element.
* Array format:
* element type
* attribute hash table
*/
void setElement (String name, int contentType,
String contentModel, Hashtable attributes)
throws java.lang.Exception
{
Object element[];
// Try looking up the element
element = (Object[])elementInfo.get(name);
// Make a new one if necessary.
if (element == null) {
element = new Object[3];
element[0] = new Integer(CONTENT_UNDECLARED);
element[1] = null;
element[2] = null;
} else if (contentType != CONTENT_UNDECLARED &&
((Integer)element[0]).intValue() != CONTENT_UNDECLARED) {
error("multiple declarations for element type", name, null);
return;
}
// Insert the content type, if any.
if (contentType != CONTENT_UNDECLARED) {
element[0] = new Integer(contentType);
}
// Insert the content model, if any.
if (contentModel != null) {
element[1] = contentModel;
}
// Insert the attributes, if any.
if (attributes != null) {
element[2] =attributes;
}
// Save the element info.
elementInfo.put(name,element);
}
/**
* Look up the attribute hash table for an element.
* The hash table is the second item in the element array.
*/
Hashtable getElementAttributes (String name)
{
Object element[] = (Object[])elementInfo.get(name);
if (element == null) {
return null;
} else {
return (Hashtable)element[2];
}
}
//
// Attributes
//
/**
* Get the declared attrib
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -