package org.owasp.webscarab.util;
import java.util.Stack;
import java.util.List;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import org.w3c.dom.ProcessingInstruction;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
public class DOMHandler implements ContentHandler, LexicalHandler {
private Document _document = null;
private Stack<Node> _stack = new Stack<Node>();
private Node _last = null;
private List<String> _namespaces = null;
public static final String XMLNS_PREFIX = "xmlns";
public static final String XMLNS_STRING = "xmlns:";
public static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
public DOMHandler() throws ParserConfigurationException {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
_document = builder.newDocument();
}
public Document getDocument() {
return _document;
}
public void characters(char[] ch, int start, int length) {
Node last = (Node)_stack.peek();
if (last != _document) {
final String text = new String(ch, start, length);
if (_last != null && _last.getNodeType() == Node.TEXT_NODE) {
((Text)_last).appendData(text);
} else{
_last = last.appendChild(_document.createTextNode(text));
}
}
}
public void startDocument() {
_stack.push(_document);
}
public void endDocument() {
_stack.pop();
}
public void startElement(String namespace, String localName, String qName, Attributes attrs) {
Element element = _document.createElementNS(namespace, qName);
// Add namespace declarations first
if (_namespaces != null) {
for (int i = 0; i < _namespaces.size(); i++) {
String prefix = (String) _namespaces.get(i++);
if (prefix == null || prefix.equals("")) {
element.setAttributeNS(XMLNS_URI, XMLNS_PREFIX, (String) _namespaces.get(i));
}
else {
element.setAttributeNS(XMLNS_URI, XMLNS_STRING + prefix, (String) _namespaces.get(i));
}
}
_namespaces.clear();
}
// Add attributes to element
final int nattrs = attrs.getLength();
for (int i = 0; i < nattrs; i++) {
if (attrs.getLocalName(i) == null) {
element.setAttribute(attrs.getQName(i), attrs.getValue(i));
}
else {
element.setAttributeNS(attrs.getURI(i), attrs.getQName(i),
attrs.getValue(i));
}
}
// Append this new node onto current stack node
Node last = (Node)_stack.peek();
last.appendChild(element);
// Push this node onto stack
_stack.push(element);
_last = null;
}
public void endElement(String namespace, String localName, String qName) {
_stack.pop();
_last = null;
}
public void startPrefixMapping(String prefix, String uri) {
if (_namespaces == null) {
_namespaces = new ArrayList<String>();
}
_namespaces.add(prefix);
_namespaces.add(uri);
}
public void endPrefixMapping(String prefix) {
// do nothing
}
public void ignorableWhitespace(char[] ch, int start, int length) {
// do nothing
}
/**
* adds processing instruction node to DOM.
*/
public void processingInstruction(String target, String data) {
Node last = (Node)_stack.peek();
ProcessingInstruction pi = _document.createProcessingInstruction(target, data);
if (pi != null){
last.appendChild(pi);
_last = pi;
}
}
public void setDocumentLocator(Locator locator) {
// do nothing
}
public void skippedEntity(String name) {
// do nothing
}
/**
* Lexical Handler method to create comment node in DOM tree.
*/
public void comment(char[] ch, int start, int length) {
Node last = (Node)_stack.peek();
Comment comment = _document.createComment(new String(ch,start,length));
if (comment != null){
last.appendChild(comment);
_last = comment;
}
}
// Lexical Handler methods- not implemented
public void startCDATA() { }
public void endCDATA() { }
public void startEntity(java.lang.String name) { }
public void endDTD() { }
public void endEntity(String name) { }
public void startDTD(String name, String publicId, String systemId) throws SAXException { }
}