| /* DomLSParser.java -- |
| Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath 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 |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| package gnu.xml.dom.ls; |
| |
| import java.io.File; |
| import java.io.InputStream; |
| import java.io.IOException; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.Arrays; |
| import java.util.List; |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.parsers.SAXParser; |
| import javax.xml.parsers.SAXParserFactory; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.DOMConfiguration; |
| import org.w3c.dom.DOMException; |
| import org.w3c.dom.DOMStringList; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.ls.DOMImplementationLS; |
| import org.w3c.dom.ls.LSException; |
| import org.w3c.dom.ls.LSInput; |
| import org.w3c.dom.ls.LSParser; |
| import org.w3c.dom.ls.LSParserFilter; |
| import org.xml.sax.EntityResolver; |
| import org.xml.sax.ErrorHandler; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXNotRecognizedException; |
| import org.xml.sax.SAXParseException; |
| import org.xml.sax.XMLReader; |
| import gnu.xml.dom.DomDocument; |
| import gnu.xml.dom.DomDOMException; |
| |
| /** |
| * Parser implementation for GNU DOM. |
| * |
| * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a> |
| */ |
| public class DomLSParser |
| implements LSParser, DOMConfiguration, DOMStringList, ErrorHandler |
| { |
| |
| private static final List SUPPORTED_PARAMETERS |
| = Arrays.asList(new String[] { "cdata-sections", |
| "comments", |
| "element-content-whitespace", |
| "namespaces", |
| "expand-entity-references", |
| "coalescing", |
| "validating", |
| "xinclude-aware", |
| "entity-resolver", |
| "error-handler" }); |
| |
| private LSParserFilter filter; |
| private final boolean async; |
| private String schemaType; |
| private SAXEventSink eventSink; |
| private SAXParserFactory factory; |
| private XMLReader reader; |
| |
| private boolean namespaceAware = true; |
| private boolean ignoreWhitespace; |
| private boolean expandEntityReferences; |
| private boolean ignoreComments; |
| private boolean coalescing; |
| private boolean validating; |
| private boolean xIncludeAware; |
| private EntityResolver entityResolver; |
| private ErrorHandler errorHandler; |
| |
| public DomLSParser(short mode, String schemaType) |
| throws DOMException |
| { |
| switch (mode) |
| { |
| case DOMImplementationLS.MODE_ASYNCHRONOUS: |
| async = true; |
| break; |
| case DOMImplementationLS.MODE_SYNCHRONOUS: |
| async = false; |
| break; |
| default: |
| throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); |
| } |
| // TODO schemaType |
| this.schemaType = schemaType; |
| factory = SAXParserFactory.newInstance(); |
| } |
| |
| // -- LSParser -- |
| |
| public DOMConfiguration getDomConfig() |
| { |
| return this; |
| } |
| |
| public LSParserFilter getFilter() |
| { |
| return filter; |
| } |
| |
| public void setFilter(LSParserFilter filter) |
| { |
| this.filter = filter; |
| } |
| |
| public boolean getAsync() |
| { |
| return async; |
| } |
| |
| public boolean getBusy() |
| { |
| return eventSink != null; |
| } |
| |
| public Document parse(LSInput input) |
| throws DOMException, LSException |
| { |
| if (async) |
| { |
| return doParse(input); |
| } |
| else |
| { |
| synchronized (this) |
| { |
| return doParse(input); |
| } |
| } |
| } |
| |
| public Document parseURI(String uri) |
| throws DOMException, LSException |
| { |
| LSInput input = new DomLSInput(); |
| input.setSystemId(uri); |
| return parse(input); |
| } |
| |
| public Node parseWithContext(LSInput input, Node context, short action) |
| throws DOMException, LSException |
| { |
| Document doc = (context.getNodeType() == Node.DOCUMENT_NODE) ? |
| (Document) context : context.getOwnerDocument(); |
| input.setBaseURI(doc.getDocumentURI()); |
| // TODO use namespaces defined on context node |
| Document ret = parse(input); |
| Node root = ret.getDocumentElement(); |
| root = doc.adoptNode(root); |
| switch (action) |
| { |
| case ACTION_APPEND_AS_CHILDREN: |
| context.appendChild(root); |
| break; |
| case ACTION_REPLACE_CHILDREN: |
| Node c1 = context.getFirstChild(); |
| while (c1 != null) |
| { |
| Node next = c1.getNextSibling(); |
| context.removeChild(c1); |
| c1 = next; |
| } |
| context.appendChild(root); |
| break; |
| case ACTION_INSERT_BEFORE: |
| Node p1 = context.getParentNode(); |
| p1.insertBefore(root, context); |
| break; |
| case ACTION_INSERT_AFTER: |
| Node p2 = context.getParentNode(); |
| Node r1 = context.getNextSibling(); |
| if (r1 == null) |
| { |
| p2.appendChild(root); |
| } |
| else |
| { |
| p2.insertBefore(root, r1); |
| } |
| break; |
| case ACTION_REPLACE: |
| Node p3 = context.getParentNode(); |
| Node r2 = context.getNextSibling(); |
| p3.removeChild(context); |
| if (r2 == null) |
| { |
| p3.appendChild(root); |
| } |
| else |
| { |
| p3.insertBefore(root, r2); |
| } |
| break; |
| } |
| return root; |
| } |
| |
| public void abort() |
| { |
| if (eventSink != null) |
| { |
| eventSink.interrupt(); |
| } |
| } |
| |
| private Document doParse(LSInput input) |
| throws DOMException, LSException |
| { |
| // create event sink |
| if (eventSink != null) |
| { |
| throw new LSException(LSException.PARSE_ERR, "parse in progress"); |
| } |
| InputSource source = getInputSource(input); |
| eventSink = (filter == null) ? new SAXEventSink() : |
| new FilteredSAXEventSink(filter); |
| // configure sink |
| eventSink.namespaceAware = namespaceAware; |
| eventSink.ignoreWhitespace = ignoreWhitespace; |
| eventSink.expandEntityReferences = expandEntityReferences; |
| eventSink.ignoreComments = ignoreComments; |
| eventSink.coalescing = coalescing; |
| // get and configure reader |
| XMLReader reader = getXMLReader(); |
| eventSink.reader = reader; |
| try |
| { |
| reader.setContentHandler(eventSink); |
| reader.setDTDHandler(eventSink); |
| reader.setProperty("http://xml.org/sax/properties/lexical-handler", |
| eventSink); |
| reader.setProperty("http://xml.org/sax/properties/declaration-handler", |
| eventSink); |
| reader.setFeature("http://xml.org/sax/features/namespaces", |
| namespaceAware); |
| reader.setFeature("http://xml.org/sax/features/namespace-prefixes", |
| true); |
| reader.setFeature("http://xml.org/sax/features/validation", |
| validating); |
| try |
| { |
| reader.setFeature("http://xml.org/sax/features/use-attributes2", |
| true); |
| } |
| catch (SAXNotRecognizedException e) |
| { |
| // ignore |
| } |
| try |
| { |
| reader.setFeature("http://xml.org/sax/features/external-general-entities", |
| true); |
| } |
| catch (SAXNotRecognizedException e) |
| { |
| // ignore |
| } |
| reader.setEntityResolver(entityResolver); |
| reader.setErrorHandler(errorHandler); |
| // parse |
| reader.parse(source); |
| } |
| catch (DOMException e) |
| { |
| reader = null; |
| eventSink = null; |
| throw e; |
| } |
| catch (SAXException e) |
| { |
| reader = null; |
| eventSink = null; |
| throw new DomLSException(LSException.PARSE_ERR, e); |
| } |
| catch (IOException e) |
| { |
| reader = null; |
| eventSink = null; |
| throw new DomLSException(LSException.PARSE_ERR, e); |
| } |
| // return document |
| Document ret = eventSink.doc; |
| String systemId = input.getSystemId(); |
| if (systemId != null && ret instanceof DomDocument) |
| { |
| ((DomDocument) ret).setDocumentURI(systemId); |
| } |
| eventSink = null; |
| return ret; |
| } |
| |
| private XMLReader getXMLReader() |
| throws LSException |
| { |
| if (reader == null) |
| { |
| factory.setNamespaceAware(namespaceAware); |
| factory.setValidating(validating); |
| factory.setXIncludeAware(xIncludeAware); |
| try |
| { |
| SAXParser parser = factory.newSAXParser(); |
| reader = parser.getXMLReader(); |
| } |
| catch (ParserConfigurationException e) |
| { |
| throw new DomLSException(LSException.PARSE_ERR, e); |
| } |
| catch (SAXException e) |
| { |
| throw new DomLSException(LSException.PARSE_ERR, e); |
| } |
| } |
| return reader; |
| } |
| |
| private InputSource getInputSource(LSInput input) |
| throws LSException |
| { |
| InputSource source = null; |
| String systemId = input.getSystemId(); |
| InputStream in = input.getByteStream(); |
| if (in != null) |
| { |
| source = new InputSource(in); |
| source.setSystemId(systemId); |
| } |
| if (source == null && entityResolver != null) |
| { |
| String publicId = input.getPublicId(); |
| try |
| { |
| source = entityResolver.resolveEntity(publicId, systemId); |
| } |
| catch (SAXException e) |
| { |
| throw new DomLSException(LSException.PARSE_ERR, e); |
| } |
| catch (IOException e) |
| { |
| throw new DomLSException(LSException.PARSE_ERR, e); |
| } |
| } |
| if (source == null) |
| { |
| URL url = null; |
| String base = input.getBaseURI(); |
| try |
| { |
| try |
| { |
| URL baseURL = (base == null) ? null : new URL(base); |
| url = (baseURL == null) ? new URL(systemId) : |
| new URL(baseURL, systemId); |
| } |
| catch (MalformedURLException e) |
| { |
| File baseFile = (base == null) ? null : new File(base); |
| url = (baseFile == null) ? new File(systemId).toURL() : |
| new File(baseFile, systemId).toURL(); |
| } |
| in = url.openStream(); |
| systemId = url.toString(); |
| source = new InputSource(in); |
| source.setSystemId(systemId); |
| } |
| catch (IOException e) |
| { |
| throw new DomLSException(LSException.PARSE_ERR, e); |
| } |
| } |
| return source; |
| } |
| |
| // -- DOMConfiguration -- |
| |
| public void setParameter(String name, Object value) |
| throws DOMException |
| { |
| name = name.toLowerCase(); |
| if ("cdata-sections".equals(name)) |
| { |
| coalescing = !((Boolean) value).booleanValue(); |
| } |
| else if ("comments".equals(name)) |
| { |
| ignoreComments = !((Boolean) value).booleanValue(); |
| } |
| else if ("element-content-whitespace".equals(name)) |
| { |
| ignoreWhitespace = !((Boolean) value).booleanValue(); |
| } |
| else if ("namespaces".equals(name)) |
| { |
| namespaceAware = ((Boolean) value).booleanValue(); |
| } |
| else if ("expand-entity-references".equals(name)) |
| { |
| expandEntityReferences = ((Boolean) value).booleanValue(); |
| } |
| else if ("coalescing".equals(name)) |
| { |
| coalescing = ((Boolean) value).booleanValue(); |
| } |
| else if ("validating".equals(name)) |
| { |
| validating = ((Boolean) value).booleanValue(); |
| } |
| else if ("xinclude-aware".equals(name)) |
| { |
| xIncludeAware = ((Boolean) value).booleanValue(); |
| } |
| else if ("entity-resolver".equals(name)) |
| { |
| entityResolver = (EntityResolver) value; |
| } |
| else if ("error-handler".equals(name)) |
| { |
| errorHandler = (ErrorHandler) value; |
| } |
| else |
| { |
| throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); |
| } |
| // invalidate reader, a new one will be created |
| reader = null; |
| } |
| |
| public Object getParameter(String name) |
| throws DOMException |
| { |
| name = name.toLowerCase(); |
| if ("cdata-sections".equals(name)) |
| { |
| return coalescing ? Boolean.FALSE : Boolean.TRUE; |
| } |
| else if ("comments".equals(name)) |
| { |
| return ignoreComments ? Boolean.FALSE : Boolean.TRUE; |
| } |
| else if ("element-content-whitespace".equals(name)) |
| { |
| return ignoreWhitespace ? Boolean.FALSE : Boolean.TRUE; |
| } |
| else if ("namespaces".equals(name)) |
| { |
| return namespaceAware ? Boolean.TRUE : Boolean.FALSE; |
| } |
| else if ("expand-entity-references".equals(name)) |
| { |
| return expandEntityReferences ? Boolean.TRUE : Boolean.FALSE; |
| } |
| else if ("coalescing".equals(name)) |
| { |
| return coalescing ? Boolean.TRUE : Boolean.FALSE; |
| } |
| else if ("validating".equals(name)) |
| { |
| return validating ? Boolean.TRUE : Boolean.FALSE; |
| } |
| else if ("xinclude-aware".equals(name)) |
| { |
| return xIncludeAware ? Boolean.TRUE : Boolean.FALSE; |
| } |
| else if ("entity-resolver".equals(name)) |
| { |
| return entityResolver; |
| } |
| else if ("error-handler".equals(name)) |
| { |
| return errorHandler; |
| } |
| else |
| { |
| throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); |
| } |
| } |
| |
| public boolean canSetParameter(String name, Object value) |
| { |
| return contains(name); |
| } |
| |
| public DOMStringList getParameterNames() |
| { |
| return this; |
| } |
| |
| // -- DOMStringList -- |
| |
| public String item(int i) |
| { |
| return (String) SUPPORTED_PARAMETERS.get(i); |
| } |
| |
| public int getLength() |
| { |
| return SUPPORTED_PARAMETERS.size(); |
| } |
| |
| public boolean contains(String str) |
| { |
| return SUPPORTED_PARAMETERS.contains(str); |
| } |
| |
| // -- ErrorHandler -- |
| |
| public void warning(SAXParseException e) |
| throws SAXException |
| { |
| if (errorHandler != null) |
| { |
| errorHandler.warning(e); |
| } |
| } |
| |
| public void error(SAXParseException e) |
| throws SAXException |
| { |
| if (errorHandler != null) |
| { |
| errorHandler.error(e); |
| } |
| } |
| |
| public void fatalError(SAXParseException e) |
| throws SAXException |
| { |
| if (errorHandler != null) |
| { |
| errorHandler.fatalError(e); |
| } |
| abort(); |
| } |
| |
| } |
| |