blob: f7dd475d9cda1c803a6dba276a935e964bba5ea8 [file] [log] [blame]
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.uibinder.rebind;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.dev.resource.ResourceOracle;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXParseException;
import org.xml.sax.ext.DefaultHandler2;
import java.util.Stack;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
/**
* Uses SAX events to construct a DOM Document. Each node in the Document will
* have a {@link XMLElement.Location} object attached to that Node's user data
* with the {@value XMLElement#LOCATION_KEY} key.
*/
class W3cDocumentBuilder extends DefaultHandler2 {
private final Document document;
private final Stack<Node> eltStack = new Stack<Node>();
private Locator locator;
private final TreeLogger logger;
private final GwtResourceEntityResolver resolver;
public W3cDocumentBuilder(TreeLogger logger, String pathBase,
ResourceOracle resourceOracle) throws ParserConfigurationException {
this.logger = logger;
document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
eltStack.push(document);
resolver = new GwtResourceEntityResolver(resourceOracle, pathBase);
}
/**
* Appends to the existing Text node, if possible.
*/
@Override
public void characters(char[] ch, int start, int length) {
Node current = eltStack.peek();
if (current.getChildNodes().getLength() == 1
&& current.getChildNodes().item(0).getNodeType() == Node.TEXT_NODE) {
Text text = (Text) current.getChildNodes().item(0);
text.appendData(new String(ch, start, length));
} else {
Text text = document.createTextNode(new String(ch, start, length));
eltStack.peek().appendChild(text);
}
}
@Override
public void endElement(String uri, String localName, String qName) {
Node elt = eltStack.pop();
assert elt.getLocalName().equals(localName);
}
@Override
public void error(SAXParseException exception) {
logger.log(Type.ERROR, exception.getMessage());
logger.log(Type.DEBUG, "SAXParseException", exception);
}
@Override
public void fatalError(SAXParseException exception) {
/*
* Fatal errors seem to be no scarier than error errors, and simply happen
* due to badly formed XML.
*/
logger.log(Type.ERROR, exception.getMessage());
logger.log(Type.DEBUG, "SAXParseException", exception);
}
public Document getDocument() {
return document;
}
@Override
public InputSource resolveEntity(String name, String publicId,
String baseURI, String systemId) {
return resolver.resolveEntity(publicId, systemId);
}
/**
* This is the whole reason for this mess. We want to know where a given
* element comes from.
*/
@Override
public void setDocumentLocator(Locator locator) {
this.locator = locator;
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) {
Element elt = document.createElementNS(uri, qName);
eltStack.peek().appendChild(elt);
eltStack.push(elt);
for (int i = 0, j = attributes.getLength(); i < j; i++) {
elt.setAttributeNS(attributes.getURI(i), attributes.getQName(i),
attributes.getValue(i));
}
XMLElement.Location location = new XMLElement.Location(
locator.getSystemId(), locator.getLineNumber());
elt.setUserData(XMLElement.LOCATION_KEY, location, null);
}
@Override
public void warning(SAXParseException exception) {
logger.log(Type.WARN, exception.getMessage());
logger.log(Type.DEBUG, "SAXParseException", exception);
}
}