| /* | |
| * 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.SAXException; | |
| import org.xml.sax.SAXParseException; | |
| import org.xml.sax.ext.DefaultHandler2; | |
| import java.io.IOException; | |
| 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) throws SAXException, IOException { | |
| 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); | |
| } | |
| } |