mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-07 05:31:22 +00:00
Implement MUCH simpler SAX-driven XML parser.
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
package net.sourceforge.guacamole.net.basic.xml;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import java.util.LinkedList;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
/**
|
||||
* A simple ContentHandler implementation which digests SAX document events and
|
||||
* produces simpler tag-level events, maintaining its own stack for the
|
||||
* convenience of the tag handlers.
|
||||
*
|
||||
* @author Mike Jumper
|
||||
*/
|
||||
public class DocumentHandler extends DefaultHandler {
|
||||
|
||||
/**
|
||||
* The name of the root element of the document.
|
||||
*/
|
||||
private String rootElementName;
|
||||
|
||||
/**
|
||||
* The handler which will be used to handle element events for the root
|
||||
* element of the document.
|
||||
*/
|
||||
private TagHandler root;
|
||||
|
||||
/**
|
||||
* The stack of all states applicable to the current parser state. Each
|
||||
* element of the stack references the TagHandler for the element being
|
||||
* parsed at that level of the document, where the current element is
|
||||
* last in the stack, and the root element is first.
|
||||
*/
|
||||
private LinkedList<DocumentHandlerState> stack =
|
||||
new LinkedList<DocumentHandlerState>();
|
||||
|
||||
/**
|
||||
* Creates a new DocumentHandler which will use the given TagHandler
|
||||
* to handle the root element.
|
||||
*
|
||||
* @param rootElementName The name of the root element of the document
|
||||
* being handled.
|
||||
* @param root The TagHandler to use for the root element.
|
||||
*/
|
||||
public DocumentHandler(String rootElementName, TagHandler root) {
|
||||
this.root = root;
|
||||
this.rootElementName = rootElementName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current element state. The current element state is the
|
||||
* state of the element the parser is currently within.
|
||||
*
|
||||
* @return The current element state.
|
||||
*/
|
||||
private DocumentHandlerState getCurrentState() {
|
||||
return stack.getLast();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName,
|
||||
Attributes attributes) throws SAXException {
|
||||
|
||||
// Get current state
|
||||
DocumentHandlerState current = getCurrentState();
|
||||
|
||||
// Handler for tag just read
|
||||
TagHandler handler;
|
||||
|
||||
// If no stack, use root handler
|
||||
if (current == null) {
|
||||
|
||||
// Validate element name
|
||||
if (!localName.equals(rootElementName))
|
||||
throw new SAXException("Root element must be '" + rootElementName + "'");
|
||||
|
||||
handler = root;
|
||||
}
|
||||
|
||||
// Otherwise, get handler from parent
|
||||
else {
|
||||
TagHandler parent_handler = current.getTagHandler();
|
||||
handler = parent_handler.childElement(localName, attributes);
|
||||
}
|
||||
|
||||
// Append new element state to stack
|
||||
stack.addLast(new DocumentHandlerState(handler));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName)
|
||||
throws SAXException {
|
||||
|
||||
// Pop last element from stack
|
||||
DocumentHandlerState completed = stack.removeLast();
|
||||
|
||||
// Finish element by sending text content
|
||||
completed.getTagHandler().complete(
|
||||
completed.getTextContent().toString());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void characters(char[] ch, int start, int length)
|
||||
throws SAXException {
|
||||
|
||||
// Append received chunk to text content
|
||||
getCurrentState().getTextContent().append(ch, start, length);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The current state of the DocumentHandler.
|
||||
*/
|
||||
private class DocumentHandlerState {
|
||||
|
||||
/**
|
||||
* The current text content of the current element being parsed.
|
||||
*/
|
||||
private StringBuilder textContent = new StringBuilder();
|
||||
|
||||
/**
|
||||
* The TagHandler which must handle document events related to the
|
||||
* element currently being parsed.
|
||||
*/
|
||||
private TagHandler tagHandler;
|
||||
|
||||
/**
|
||||
* Creates a new DocumentHandlerState which will maintain the state
|
||||
* of parsing of the current element, as well as contain the TagHandler
|
||||
* which will receive events related to that element.
|
||||
*
|
||||
* @param tagHandler The TagHandler which should receive any events
|
||||
* related to the element being parsed.
|
||||
*/
|
||||
public DocumentHandlerState(TagHandler tagHandler) {
|
||||
this.tagHandler = tagHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mutable StringBuilder which contains the current text
|
||||
* content of the element being parsed.
|
||||
*
|
||||
* @return The mutable StringBuilder which contains the current text
|
||||
* content of the element being parsed.
|
||||
*/
|
||||
public StringBuilder getTextContent() {
|
||||
return textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the TagHandler which must handle any events relating to the
|
||||
* element being parsed.
|
||||
*
|
||||
* @return The TagHandler which must handle any events relating to the
|
||||
* element being parsed.
|
||||
*/
|
||||
public TagHandler getTagHandler() {
|
||||
return tagHandler;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
package net.sourceforge.guacamole.net.basic.xml;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* A simple element-level event handler for events triggered by the
|
||||
* SAX-driven DocumentHandler parser.
|
||||
*
|
||||
* @author Mike Jumper
|
||||
*/
|
||||
public interface TagHandler {
|
||||
|
||||
/**
|
||||
* Called when a child element of the current element is parsed.
|
||||
*
|
||||
* @param localName The local name of the child element seen.
|
||||
* @param attributes The attributes of the child element seen.
|
||||
* @return The TagHandler which should handle all element-level events
|
||||
* related to the child element.
|
||||
* @throws SAXException If the child element being parsed was not expected,
|
||||
* or some other error prevents a proper TagHandler
|
||||
* from being constructed for the child element.
|
||||
*/
|
||||
public TagHandler childElement(String localName, Attributes attributes)
|
||||
throws SAXException;
|
||||
|
||||
/**
|
||||
* Called when this element, and all child elements, have been fully parsed,
|
||||
* and the entire text content of this element (if any) is available.
|
||||
*
|
||||
* @param textContent The full text content of this element, if any.
|
||||
* @throws SAXException If the text content received is not valid for any
|
||||
* reason, or the child elements parsed are not
|
||||
* correct.
|
||||
*/
|
||||
public void complete(String textContent) throws SAXException;
|
||||
|
||||
}
|
Reference in New Issue
Block a user