Makefile.am: New file.

* external/w3c_dom/Makefile.am: New file.
	* external/w3c_dom/Makefile.in: New file.
	* external/sax/Makefile.am: New file.
	* external/sax/Makefile.in: New file.
	* external/Makefile.in: New file.
	* external/Makefile.am: New file.
	* external/README: New file from Classpath.
	* configure, aclocal.m4, Makefile.in: Rebuilt.
	* configure.ac (AC_CONFIG_FILES): Create new Makefiles.
	* Makefile.am (SUBDIRS): Added external.
	(toolexeclib_LTLIBRARIES): Removed lib-org-xml-sax.la,
	lib-org-w3c-dom.la, lib-org-ietf-gss.la.
	(BOOTCLASSPATH): New variable.
	(AM_GCJFLAGS): Use it.
	(gnu_xml_source_files): New variable.
	(libgcj_la_SOURCES): Use it.
	(libgcj_la_LDADD): Include new convenience libraries.
	(lib_org_ietf_jgss_la_SOURCES): Removed.
	(lib_org_ietf_jgss_la_DEPENDENCIES): Likewise.
	(lib_org_ietf_jgss_la_LIBADD): Likewise.
	(lib_org_w3c_dom_la_SOURCES): Removed.
	(lib_org_w3c_dom_la_DEPENDENCIES): Likewise.
	(lib_org_w3c_dom_la_LIBADD): Likewise.
	(lib_org_xml_sax_la_SOURCES): Removed.
	(lib_org_xml_sax_la_DEPENDENCIES): Likewise.
	(lib_org_xml_sax_la_LIBADD): Likewise.
	(all_java_source_files): Updated.
	(property_files): Likewise.
	(libgcj-@gcc_version@.jar): Include classes from external/.
	(javax_source_files): Updated.
	(ordinary_java_source_files): Updated.
	* javax/xml/XMLConstants.java,
	javax/xml/datatype/DatatypeConfigurationException.java,
	javax/xml/datatype/DatatypeConstants.java,
	javax/xml/datatype/DatatypeFactory.java,
	javax/xml/datatype/Duration.java,
	javax/xml/datatype/XMLGregorianCalendar.java,
	javax/xml/datatype/package.html,
	javax/xml/namespace/NamespaceContext.java,
	javax/xml/namespace/QName.java, javax/xml/namespace/package.html,
	javax/xml/parsers/DocumentBuilder.java,
	javax/xml/parsers/DocumentBuilderFactory.java,
	javax/xml/parsers/FactoryConfigurationError.java,
	javax/xml/parsers/ParserConfigurationException.java,
	javax/xml/parsers/SAXParser.java,
	javax/xml/parsers/SAXParserFactory.java,
	javax/xml/parsers/package.html,
	javax/xml/transform/ErrorListener.java,
	javax/xml/transform/OutputKeys.java,
	javax/xml/transform/Result.java, javax/xml/transform/Source.java,
	javax/xml/transform/SourceLocator.java,
	javax/xml/transform/Templates.java,
	javax/xml/transform/Transformer.java,
	javax/xml/transform/TransformerConfigurationException.java,
	javax/xml/transform/TransformerException.java,
	javax/xml/transform/TransformerFactory.java,
	javax/xml/transform/TransformerFactoryConfigurationError.java,
	javax/xml/transform/URIResolver.java,
	javax/xml/transform/package.html,
	javax/xml/transform/dom/DOMLocator.java,
	javax/xml/transform/dom/DOMResult.java,
	javax/xml/transform/dom/DOMSource.java,
	javax/xml/transform/dom/package.html,
	javax/xml/transform/sax/SAXResult.java,
	javax/xml/transform/sax/SAXSource.java,
	javax/xml/transform/sax/SAXTransformerFactory.java,
	javax/xml/transform/sax/TemplatesHandler.java,
	javax/xml/transform/sax/TransformerHandler.java,
	javax/xml/transform/sax/package.html,
	javax/xml/transform/stream/StreamResult.java,
	javax/xml/transform/stream/StreamSource.java,
	javax/xml/transform/stream/package.html,
	javax/xml/validation/Schema.java,
	javax/xml/validation/SchemaFactory.java,
	javax/xml/validation/TypeInfoProvider.java,
	javax/xml/validation/Validator.java,
	javax/xml/validation/ValidatorHandler.java,
	javax/xml/validation/package.html, javax/xml/xpath/XPath.java,
	javax/xml/xpath/XPathConstants.java,
	javax/xml/xpath/XPathException.java,
	javax/xml/xpath/XPathExpression.java,
	javax/xml/xpath/XPathExpressionException.java,
	javax/xml/xpath/XPathFactory.java,
	javax/xml/xpath/XPathFactoryConfigurationException.java,
	javax/xml/xpath/XPathFunction.java,
	javax/xml/xpath/XPathFunctionException.java,
	javax/xml/xpath/XPathFunctionResolver.java,
	javax/xml/xpath/XPathVariableResolver.java,
	javax/xml/xpath/package.html: New files, from GNU JAXP.
	* org/w3c/dom/Attr.java, org/w3c/dom/CDATASection.java,
	org/w3c/dom/CharacterData.java, org/w3c/dom/Comment.java,
	org/w3c/dom/DOMException.java, org/w3c/dom/DOMImplementation.java,
	org/w3c/dom/Document.java, org/w3c/dom/DocumentFragment.java,
	org/w3c/dom/DocumentType.java, org/w3c/dom/Element.java,
	org/w3c/dom/Entity.java, org/w3c/dom/EntityReference.java,
	org/w3c/dom/NamedNodeMap.java, org/w3c/dom/Node.java,
	org/w3c/dom/NodeList.java, org/w3c/dom/Notation.java,
	org/w3c/dom/ProcessingInstruction.java, org/w3c/dom/Text.java,
	org/w3c/dom/ranges/DocumentRange.java,
	org/w3c/dom/ranges/Range.java,
	org/w3c/dom/ranges/RangeException.java,
	org/w3c/dom/traversal/DocumentTraversal.java,
	org/w3c/dom/traversal/NodeFilter.java,
	org/w3c/dom/traversal/NodeIterator.java,
	org/w3c/dom/traversal/TreeWalker.java,
	org/xml/sax/AttributeList.java, org/xml/sax/Attributes.java,
	org/xml/sax/ContentHandler.java, org/xml/sax/DTDHandler.java,
	org/xml/sax/DocumentHandler.java, org/xml/sax/EntityResolver.java,
	org/xml/sax/ErrorHandler.java, org/xml/sax/HandlerBase.java,
	org/xml/sax/InputSource.java, org/xml/sax/Locator.java,
	org/xml/sax/Parser.java, org/xml/sax/SAXException.java,
	org/xml/sax/SAXNotRecognizedException.java,
	org/xml/sax/SAXNotSupportedException.java,
	org/xml/sax/SAXParseException.java, org/xml/sax/XMLFilter.java,
	org/xml/sax/XMLReader.java, org/xml/sax/package.html,
	org/xml/sax/ext/DeclHandler.java,
	org/xml/sax/ext/LexicalHandler.java, org/xml/sax/ext/package.html,
	org/xml/sax/helpers/AttributeListImpl.java,
	org/xml/sax/helpers/AttributesImpl.java,
	org/xml/sax/helpers/DefaultHandler.java,
	org/xml/sax/helpers/LocatorImpl.java,
	org/xml/sax/helpers/NamespaceSupport.java,
	org/xml/sax/helpers/NewInstance.java,
	org/xml/sax/helpers/ParserAdapter.java,
	org/xml/sax/helpers/ParserFactory.java,
	org/xml/sax/helpers/XMLFilterImpl.java,
	org/xml/sax/helpers/XMLReaderAdapter.java,
	org/xml/sax/helpers/XMLReaderFactory.java,
	org/xml/sax/helpers/package.html: Moved to external/.
	* external/sax/README,
	external/sax/org/xml/sax/AttributeList.java,
	external/sax/org/xml/sax/Attributes.java,
	external/sax/org/xml/sax/ContentHandler.java,
	external/sax/org/xml/sax/DTDHandler.java,
	external/sax/org/xml/sax/DocumentHandler.java,
	external/sax/org/xml/sax/EntityResolver.java,
	external/sax/org/xml/sax/ErrorHandler.java,
	external/sax/org/xml/sax/HandlerBase.java,
	external/sax/org/xml/sax/InputSource.java,
	external/sax/org/xml/sax/Locator.java,
	external/sax/org/xml/sax/Parser.java,
	external/sax/org/xml/sax/SAXException.java,
	external/sax/org/xml/sax/SAXNotRecognizedException.java,
	external/sax/org/xml/sax/SAXNotSupportedException.java,
	external/sax/org/xml/sax/SAXParseException.java,
	external/sax/org/xml/sax/XMLFilter.java,
	external/sax/org/xml/sax/XMLReader.java,
	external/sax/org/xml/sax/package.html,
	external/sax/org/xml/sax/ext/Attributes2.java,
	external/sax/org/xml/sax/ext/Attributes2Impl.java,
	external/sax/org/xml/sax/ext/DeclHandler.java,
	external/sax/org/xml/sax/ext/DefaultHandler2.java,
	external/sax/org/xml/sax/ext/EntityResolver2.java,
	external/sax/org/xml/sax/ext/LexicalHandler.java,
	external/sax/org/xml/sax/ext/Locator2.java,
	external/sax/org/xml/sax/ext/Locator2Impl.java,
	external/sax/org/xml/sax/ext/package.html,
	external/sax/org/xml/sax/helpers/AttributeListImpl.java,
	external/sax/org/xml/sax/helpers/AttributesImpl.java,
	external/sax/org/xml/sax/helpers/DefaultHandler.java,
	external/sax/org/xml/sax/helpers/LocatorImpl.java,
	external/sax/org/xml/sax/helpers/NamespaceSupport.java,
	external/sax/org/xml/sax/helpers/NewInstance.java,
	external/sax/org/xml/sax/helpers/ParserAdapter.java,
	external/sax/org/xml/sax/helpers/ParserFactory.java,
	external/sax/org/xml/sax/helpers/XMLFilterImpl.java,
	external/sax/org/xml/sax/helpers/XMLReaderAdapter.java,
	external/sax/org/xml/sax/helpers/XMLReaderFactory.java,
	external/sax/org/xml/sax/helpers/package.html,
	external/w3c_dom/COPYRIGHT.html, external/w3c_dom/README,
	external/w3c_dom/org/w3c/dom/Attr.java,
	external/w3c_dom/org/w3c/dom/CDATASection.java,
	external/w3c_dom/org/w3c/dom/CharacterData.java,
	external/w3c_dom/org/w3c/dom/Comment.java,
	external/w3c_dom/org/w3c/dom/DOMConfiguration.java,
	external/w3c_dom/org/w3c/dom/DOMError.java,
	external/w3c_dom/org/w3c/dom/DOMErrorHandler.java,
	external/w3c_dom/org/w3c/dom/DOMException.java,
	external/w3c_dom/org/w3c/dom/DOMImplementation.java,
	external/w3c_dom/org/w3c/dom/DOMImplementationList.java,
	external/w3c_dom/org/w3c/dom/DOMImplementationSource.java,
	external/w3c_dom/org/w3c/dom/DOMLocator.java,
	external/w3c_dom/org/w3c/dom/DOMStringList.java,
	external/w3c_dom/org/w3c/dom/Document.java,
	external/w3c_dom/org/w3c/dom/DocumentFragment.java,
	external/w3c_dom/org/w3c/dom/DocumentType.java,
	external/w3c_dom/org/w3c/dom/Element.java,
	external/w3c_dom/org/w3c/dom/Entity.java,
	external/w3c_dom/org/w3c/dom/EntityReference.java,
	external/w3c_dom/org/w3c/dom/NameList.java,
	external/w3c_dom/org/w3c/dom/NamedNodeMap.java,
	external/w3c_dom/org/w3c/dom/Node.java,
	external/w3c_dom/org/w3c/dom/NodeList.java,
	external/w3c_dom/org/w3c/dom/Notation.java,
	external/w3c_dom/org/w3c/dom/ProcessingInstruction.java,
	external/w3c_dom/org/w3c/dom/Text.java,
	external/w3c_dom/org/w3c/dom/TypeInfo.java,
	external/w3c_dom/org/w3c/dom/UserDataHandler.java,
	external/w3c_dom/org/w3c/dom/bootstrap/DOMImplementationRegistry.java,
	external/w3c_dom/org/w3c/dom/css/CSS2Properties.java,
	external/w3c_dom/org/w3c/dom/css/CSSCharsetRule.java,
	external/w3c_dom/org/w3c/dom/css/CSSFontFaceRule.java,
	external/w3c_dom/org/w3c/dom/css/CSSImportRule.java,
	external/w3c_dom/org/w3c/dom/css/CSSMediaRule.java,
	external/w3c_dom/org/w3c/dom/css/CSSPageRule.java,
	external/w3c_dom/org/w3c/dom/css/CSSPrimitiveValue.java,
	external/w3c_dom/org/w3c/dom/css/CSSRule.java,
	external/w3c_dom/org/w3c/dom/css/CSSRuleList.java,
	external/w3c_dom/org/w3c/dom/css/CSSStyleDeclaration.java,
	external/w3c_dom/org/w3c/dom/css/CSSStyleRule.java,
	external/w3c_dom/org/w3c/dom/css/CSSStyleSheet.java,
	external/w3c_dom/org/w3c/dom/css/CSSUnknownRule.java,
	external/w3c_dom/org/w3c/dom/css/CSSValue.java,
	external/w3c_dom/org/w3c/dom/css/CSSValueList.java,
	external/w3c_dom/org/w3c/dom/css/Counter.java,
	external/w3c_dom/org/w3c/dom/css/DOMImplementationCSS.java,
	external/w3c_dom/org/w3c/dom/css/DocumentCSS.java,
	external/w3c_dom/org/w3c/dom/css/ElementCSSInlineStyle.java,
	external/w3c_dom/org/w3c/dom/css/RGBColor.java,
	external/w3c_dom/org/w3c/dom/css/Rect.java,
	external/w3c_dom/org/w3c/dom/css/ViewCSS.java,
	external/w3c_dom/org/w3c/dom/events/DocumentEvent.java,
	external/w3c_dom/org/w3c/dom/events/Event.java,
	external/w3c_dom/org/w3c/dom/events/EventException.java,
	external/w3c_dom/org/w3c/dom/events/EventListener.java,
	external/w3c_dom/org/w3c/dom/events/EventTarget.java,
	external/w3c_dom/org/w3c/dom/events/MouseEvent.java,
	external/w3c_dom/org/w3c/dom/events/MutationEvent.java,
	external/w3c_dom/org/w3c/dom/events/UIEvent.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLAnchorElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLAppletElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLAreaElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLBRElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLBaseElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLBaseFontElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLBodyElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLButtonElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLCollection.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLDListElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLDirectoryElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLDivElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLDocument.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLFieldSetElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLFontElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLFormElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLFrameElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLFrameSetElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLHRElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLHeadElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLHeadingElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLHtmlElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLIFrameElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLImageElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLInputElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLIsIndexElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLLIElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLLabelElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLLegendElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLLinkElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLMapElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLMenuElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLMetaElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLModElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLOListElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLObjectElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLOptGroupElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLOptionElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLOptionsCollection.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLParagraphElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLParamElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLPreElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLQuoteElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLScriptElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLSelectElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLStyleElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLTableCaptionElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLTableCellElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLTableColElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLTableElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLTableRowElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLTableSectionElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLTextAreaElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLTitleElement.java,
	external/w3c_dom/org/w3c/dom/html2/HTMLUListElement.java,
	external/w3c_dom/org/w3c/dom/ls/DOMImplementationLS.java,
	external/w3c_dom/org/w3c/dom/ls/LSException.java,
	external/w3c_dom/org/w3c/dom/ls/LSInput.java,
	external/w3c_dom/org/w3c/dom/ls/LSLoadEvent.java,
	external/w3c_dom/org/w3c/dom/ls/LSOutput.java,
	external/w3c_dom/org/w3c/dom/ls/LSParser.java,
	external/w3c_dom/org/w3c/dom/ls/LSParserFilter.java,
	external/w3c_dom/org/w3c/dom/ls/LSProgressEvent.java,
	external/w3c_dom/org/w3c/dom/ls/LSResourceResolver.java,
	external/w3c_dom/org/w3c/dom/ls/LSSerializer.java,
	external/w3c_dom/org/w3c/dom/ls/LSSerializerFilter.java,
	external/w3c_dom/org/w3c/dom/ranges/DocumentRange.java,
	external/w3c_dom/org/w3c/dom/ranges/Range.java,
	external/w3c_dom/org/w3c/dom/ranges/RangeException.java,
	external/w3c_dom/org/w3c/dom/stylesheets/DocumentStyle.java,
	external/w3c_dom/org/w3c/dom/stylesheets/LinkStyle.java,
	external/w3c_dom/org/w3c/dom/stylesheets/MediaList.java,
	external/w3c_dom/org/w3c/dom/stylesheets/StyleSheet.java,
	external/w3c_dom/org/w3c/dom/stylesheets/StyleSheetList.java,
	external/w3c_dom/org/w3c/dom/traversal/DocumentTraversal.java,
	external/w3c_dom/org/w3c/dom/traversal/NodeFilter.java,
	external/w3c_dom/org/w3c/dom/traversal/NodeIterator.java,
	external/w3c_dom/org/w3c/dom/traversal/TreeWalker.java,
	external/w3c_dom/org/w3c/dom/views/AbstractView.java,
	external/w3c_dom/org/w3c/dom/views/DocumentView.java,
	external/w3c_dom/org/w3c/dom/xpath/XPathEvaluator.java,
	external/w3c_dom/org/w3c/dom/xpath/XPathException.java,
	external/w3c_dom/org/w3c/dom/xpath/XPathExpression.java,
	external/w3c_dom/org/w3c/dom/xpath/XPathNSResolver.java,
	external/w3c_dom/org/w3c/dom/xpath/XPathNamespace.java,
	external/w3c_dom/org/w3c/dom/xpath/XPathResult.java: New files
	from Classpath.

From-SVN: r94577
This commit is contained in:
Tom Tromey
2005-02-02 00:42:32 +00:00
committed by Tom Tromey
parent c1c5b5e383
commit 9ecd03471f
453 changed files with 88593 additions and 6760 deletions
+250
View File
@@ -0,0 +1,250 @@
/* CallFilter.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., 59 Temple Place, Suite 330, Boston, MA
02111-1307 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.pipeline;
import java.io.*;
import java.net.*;
import org.xml.sax.*;
import org.xml.sax.ext.*;
import org.xml.sax.helpers.XMLReaderFactory;
import gnu.xml.util.Resolver;
import gnu.xml.util.XMLWriter;
/**
* Input is sent as an XML request to given URI, and the output of this
* filter is the parsed response to that request.
* A connection is opened to the remote URI when the startDocument call is
* issued through this filter, and the request is finished when the
* endDocument call is issued. Events should be written quickly enough to
* prevent the remote HTTP server from aborting the connection due to
* inactivity; you may want to buffer text in an earlier pipeline stage.
* If your application requires validity checking of such
* outputs, have the output pipeline include a validation stage.
*
* <p>In effect, this makes a remote procedure call to the URI, with the
* request and response document syntax as chosen by the application.
* <em>Note that all the input events must be seen, and sent to the URI,
* before the first output event can be seen. </em> Clients are delayed
* at least by waiting for the server to respond, constraining concurrency.
* Services can thus be used to synchronize concurrent activities, and
* even to prioritize service among different clients.
*
* <p> You are advised to avoid restricting yourself to an "RPC" model
* for distributed computation. With a World Wide Web, network latencies
* and failures (e.g. non-availability)
* are significant; adopting a "procedure" model, rather than a workflow
* model where bulk requests are sent and worked on asynchronously, is not
* generally an optimal system-wide architecture. When the messages may
* need authentication, such as with an OpenPGP signature, or when server
* loads don't argue in favor of immediate responses, non-RPC models can
* be advantageous. (So-called "peer to peer" computing models are one
* additional type of model, though too often that term is applied to
* systems that still have a centralized control structure.)
*
* <p> <em>Be strict in what you send, liberal in what you accept,</em> as
* the Internet tradition goes. Strictly conformant data should never cause
* problems to its receiver; make your request pipeline be very strict, and
* don't compromise on that. Make your response pipeline strict as well,
* but be ready to tolerate specific mild, temporary, and well-documented
* variations from specific communications peers.
*
* @see XmlServlet
*
* @author David Brownell
*/
final public class CallFilter implements EventConsumer
{
private Requestor req;
private EventConsumer next;
private URL target;
private URLConnection conn;
private ErrorHandler errHandler;
/**
* Initializes a call filter so that its inputs are sent to the
* specified URI, and its outputs are sent to the next consumer
* provided.
*
* @exception IOException if the URI isn't accepted as a URL
*/
// constructor used by PipelineFactory
public CallFilter (String uri, EventConsumer next)
throws IOException
{
this.next = next;
req = new Requestor ();
setCallTarget (uri);
}
/**
* Assigns the URI of the call target to be used.
* Does not affect calls currently being made.
*/
final public void setCallTarget (String uri)
throws IOException
{
target = new URL (uri);
}
/**
* Assigns the error handler to be used to present most fatal
* errors.
*/
public void setErrorHandler (ErrorHandler handler)
{
req.setErrorHandler (handler);
}
/**
* Returns the call target's URI.
*/
final public String getCallTarget ()
{
return target.toString ();
}
/** Returns the content handler currently in use. */
final public org.xml.sax.ContentHandler getContentHandler ()
{
return req;
}
/** Returns the DTD handler currently in use. */
final public DTDHandler getDTDHandler ()
{
return req;
}
/**
* Returns the declaration or lexical handler currently in
* use, or throws an exception for other properties.
*/
final public Object getProperty (String id)
throws SAXNotRecognizedException
{
if (EventFilter.DECL_HANDLER.equals (id))
return req;
if (EventFilter.LEXICAL_HANDLER.equals (id))
return req;
throw new SAXNotRecognizedException (id);
}
// JDK 1.1 seems to need it to be done this way, sigh
ErrorHandler getErrorHandler () { return errHandler; }
//
// Takes input and echoes to server as POST input.
// Then sends the POST reply to the next pipeline element.
//
final class Requestor extends XMLWriter
{
Requestor ()
{
super ((Writer)null);
}
public synchronized void startDocument () throws SAXException
{
// Connect to remote object and set up to send it XML text
try {
if (conn != null)
throw new IllegalStateException ("call is being made");
conn = target.openConnection ();
conn.setDoOutput (true);
conn.setRequestProperty ("Content-Type",
"application/xml;charset=UTF-8");
setWriter (new OutputStreamWriter (
conn.getOutputStream (),
"UTF8"), "UTF-8");
} catch (IOException e) {
fatal ("can't write (POST) to URI: " + target, e);
}
// NOW base class can safely write that text!
super.startDocument ();
}
public void endDocument () throws SAXException
{
//
// Finish writing the request (for HTTP, a POST);
// this closes the output stream.
//
super.endDocument ();
//
// Receive the response.
// Produce events for the next stage.
//
InputSource source;
XMLReader producer;
String encoding;
try {
source = new InputSource (conn.getInputStream ());
// FIXME if status is anything but success, report it!! It'd be good to
// save the request data just in case we need to deal with a forward.
encoding = Resolver.getEncoding (conn.getContentType ());
if (encoding != null)
source.setEncoding (encoding);
producer = XMLReaderFactory.createXMLReader ();
producer.setErrorHandler (getErrorHandler ());
EventFilter.bind (producer, next);
producer.parse (source);
conn = null;
} catch (IOException e) {
fatal ("I/O Exception reading response, " + e.getMessage (), e);
}
}
}
}
+969
View File
@@ -0,0 +1,969 @@
/* DomConsumer.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., 59 Temple Place, Suite 330, Boston, MA
02111-1307 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.pipeline;
import java.util.Hashtable;
import org.w3c.dom.*;
import org.xml.sax.*;
import org.xml.sax.ext.DeclHandler;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.helpers.AttributesImpl;
import gnu.xml.aelfred2.ContentHandler2;
import gnu.xml.util.DomParser;
/**
* This consumer builds a DOM Document from its input, acting either as a
* pipeline terminus or as an intermediate buffer. When a document's worth
* of events has been delivered to this consumer, that document is read with
* a {@link DomParser} and sent to the next consumer. It is also available
* as a read-once property.
*
* <p>The DOM tree is constructed as faithfully as possible. There are some
* complications since a DOM should expose behaviors that can't be implemented
* without API backdoors into that DOM, and because some SAX parsers don't
* report all the information that DOM permits to be exposed. The general
* problem areas involve information from the Document Type Declaration (DTD).
* DOM only represents a limited subset, but has some behaviors that depend
* on much deeper knowledge of a document's DTD. You shouldn't have much to
* worry about unless you change handling of "noise" nodes from its default
* setting (which ignores them all); note if you use JAXP to populate your
* DOM trees, it wants to save "noise" nodes by default. (Such nodes include
* ignorable whitespace, comments, entity references and CDATA boundaries.)
* Otherwise, your
* main worry will be if you use a SAX parser that doesn't flag ignorable
* whitespace unless it's validating (few don't).
*
* <p> The SAX2 events used as input must contain XML Names for elements
* and attributes, with original prefixes. In SAX2,
* this is optional unless the "namespace-prefixes" parser feature is set.
* Moreover, many application components won't provide completely correct
* structures anyway. <em>Before you convert a DOM to an output document,
* you should plan to postprocess it to create or repair such namespace
* information.</em> The {@link NSFilter} pipeline stage does such work.
*
* <p> <em>Note: changes late in DOM L2 process made it impractical to
* attempt to create the DocumentType node in any implementation-neutral way,
* much less to populate it (L1 didn't support even creating such nodes).
* To create and populate such a node, subclass the inner
* {@link DomConsumer.Handler} class and teach it about the backdoors into
* whatever DOM implementation you want. It's possible that some revised
* DOM API (L3?) will make this problem solvable again. </em>
*
* @see DomParser
*
* @author David Brownell
*/
public class DomConsumer implements EventConsumer
{
private Class domImpl;
private boolean hidingCDATA = true;
private boolean hidingComments = true;
private boolean hidingWhitespace = true;
private boolean hidingReferences = true;
private Handler handler;
private ErrorHandler errHandler;
private EventConsumer next;
// FIXME: this can't be a generic pipeline stage just now,
// since its input became a Class not a String (to be turned
// into a class, using the right class loader)
/**
* Configures this pipeline terminus to use the specified implementation
* of DOM when constructing its result value.
*
* @param impl class implementing {@link org.w3c.dom.Document Document}
* which publicly exposes a default constructor
*
* @exception SAXException when there is a problem creating an
* empty DOM document using the specified implementation
*/
public DomConsumer (Class impl)
throws SAXException
{
domImpl = impl;
handler = new Handler (this);
}
/**
* This is the hook through which a subclass provides a handler
* which knows how to access DOM extensions, specific to some
* implementation, to record additional data in a DOM.
* Treat this as part of construction; don't call it except
* before (or between) parses.
*/
protected void setHandler (Handler h)
{
handler = h;
}
private Document emptyDocument ()
throws SAXException
{
try {
return (Document) domImpl.newInstance ();
} catch (IllegalAccessException e) {
throw new SAXException ("can't access constructor: "
+ e.getMessage ());
} catch (InstantiationException e) {
throw new SAXException ("can't instantiate Document: "
+ e.getMessage ());
}
}
/**
* Configures this consumer as a buffer/filter, using the specified
* DOM implementation when constructing its result value.
*
* <p> This event consumer acts as a buffer and filter, in that it
* builds a DOM tree and then writes it out when <em>endDocument</em>
* is invoked. Because of the limitations of DOM, much information
* will as a rule not be seen in that replay. To get a full fidelity
* copy of the input event stream, use a {@link TeeConsumer}.
*
* @param impl class implementing {@link org.w3c.dom.Document Document}
* which publicly exposes a default constructor
* @param next receives a "replayed" sequence of parse events when
* the <em>endDocument</em> method is invoked.
*
* @exception SAXException when there is a problem creating an
* empty DOM document using the specified DOM implementation
*/
public DomConsumer (Class impl, EventConsumer n)
throws SAXException
{
this (impl);
next = n;
}
/**
* Returns the document constructed from the preceding
* sequence of events. This method should not be
* used again until another sequence of events has been
* given to this EventConsumer.
*/
final public Document getDocument ()
{
return handler.clearDocument ();
}
public void setErrorHandler (ErrorHandler handler)
{
errHandler = handler;
}
/**
* Returns true if the consumer is hiding entity references nodes
* (the default), and false if EntityReference nodes should
* instead be created. Such EntityReference nodes will normally be
* empty, unless an implementation arranges to populate them and then
* turn them back into readonly objects.
*
* @see #setHidingReferences
*/
final public boolean isHidingReferences ()
{ return hidingReferences; }
/**
* Controls whether the consumer will hide entity expansions,
* or will instead mark them with entity reference nodes.
*
* @see #isHidingReferences
* @param flag False if entity reference nodes will appear
*/
final public void setHidingReferences (boolean flag)
{ hidingReferences = flag; }
/**
* Returns true if the consumer is hiding comments (the default),
* and false if they should be placed into the output document.
*
* @see #setHidingComments
*/
public final boolean isHidingComments ()
{ return hidingComments; }
/**
* Controls whether the consumer is hiding comments.
*
* @see #isHidingComments
*/
public final void setHidingComments (boolean flag)
{ hidingComments = flag; }
/**
* Returns true if the consumer is hiding ignorable whitespace
* (the default), and false if such whitespace should be placed
* into the output document as children of element nodes.
*
* @see #setHidingWhitespace
*/
public final boolean isHidingWhitespace ()
{ return hidingWhitespace; }
/**
* Controls whether the consumer hides ignorable whitespace
*
* @see #isHidingComments
*/
public final void setHidingWhitespace (boolean flag)
{ hidingWhitespace = flag; }
/**
* Returns true if the consumer is saving CDATA boundaries, or
* false (the default) otherwise.
*
* @see #setHidingCDATA
*/
final public boolean isHidingCDATA ()
{ return hidingCDATA; }
/**
* Controls whether the consumer will save CDATA boundaries.
*
* @see #isHidingCDATA
* @param flag True to treat CDATA text differently from other
* text nodes
*/
final public void setHidingCDATA (boolean flag)
{ hidingCDATA = flag; }
/** Returns the document handler being used. */
final public ContentHandler getContentHandler ()
{ return handler; }
/** Returns the DTD handler being used. */
final public DTDHandler getDTDHandler ()
{ return handler; }
/**
* Returns the lexical handler being used.
* (DOM construction can't really use declaration handlers.)
*/
final public Object getProperty (String id)
throws SAXNotRecognizedException
{
if ("http://xml.org/sax/properties/lexical-handler".equals (id))
return handler;
if ("http://xml.org/sax/properties/declaration-handler".equals (id))
return handler;
throw new SAXNotRecognizedException (id);
}
EventConsumer getNext () { return next; }
ErrorHandler getErrorHandler () { return errHandler; }
/**
* Class used to intercept various parsing events and use them to
* populate a DOM document. Subclasses would typically know and use
* backdoors into specific DOM implementations, used to implement
* DTD-related functionality.
*
* <p> Note that if this ever throws a DOMException (runtime exception)
* that will indicate a bug in the DOM (e.g. doesn't support something
* per specification) or the parser (e.g. emitted an illegal name, or
* accepted illegal input data). </p>
*/
public static class Handler
implements ContentHandler2, LexicalHandler,
DTDHandler, DeclHandler
{
protected DomConsumer consumer;
private DOMImplementation impl;
private Document document;
private boolean isL2;
private Locator locator;
private Node top;
private boolean inCDATA;
private boolean mergeCDATA;
private boolean inDTD;
private String currentEntity;
private boolean recreatedAttrs;
private AttributesImpl attributes = new AttributesImpl ();
/**
* Subclasses may use SAX2 events to provide additional
* behaviors in the resulting DOM.
*/
protected Handler (DomConsumer consumer)
throws SAXException
{
this.consumer = consumer;
document = consumer.emptyDocument ();
impl = document.getImplementation ();
isL2 = impl.hasFeature ("XML", "2.0");
}
private void fatal (String message, Exception x)
throws SAXException
{
SAXParseException e;
ErrorHandler errHandler = consumer.getErrorHandler ();;
if (locator == null)
e = new SAXParseException (message, null, null, -1, -1, x);
else
e = new SAXParseException (message, locator, x);
if (errHandler != null)
errHandler.fatalError (e);
throw e;
}
/**
* Returns and forgets the document produced. If the handler is
* reused, a new document may be created.
*/
Document clearDocument ()
{
Document retval = document;
document = null;
locator = null;
return retval;
}
/**
* Returns the document under construction.
*/
protected Document getDocument ()
{ return document; }
/**
* Returns the current node being populated. This is usually
* an Element or Document, but it might be an EntityReference
* node if some implementation-specific code knows how to put
* those into the result tree and later mark them as readonly.
*/
protected Node getTop ()
{ return top; }
// SAX1
public void setDocumentLocator (Locator locator)
{
this.locator = locator;
}
// SAX1
public void startDocument ()
throws SAXException
{
if (document == null)
try {
if (isL2) {
// couple to original implementation
document = impl.createDocument (null, "foo", null);
document.removeChild (document.getFirstChild ());
} else {
document = consumer.emptyDocument ();
}
} catch (Exception e) {
fatal ("DOM create document", e);
}
top = document;
}
// ContentHandler2
public void xmlDecl(String version,
String encoding,
boolean standalone,
String inputEncoding)
throws SAXException
{
if (document != null)
{
document.setXmlVersion(version);
document.setXmlStandalone(standalone);
}
}
// SAX1
public void endDocument ()
throws SAXException
{
try {
if (consumer.getNext () != null && document != null) {
DomParser parser = new DomParser (document);
EventFilter.bind (parser, consumer.getNext ());
parser.parse ("ignored");
}
} finally {
top = null;
}
}
// SAX1
public void processingInstruction (String target, String data)
throws SAXException
{
// we can't create populated entity ref nodes using
// only public DOM APIs (they've got to be readonly)
if (currentEntity != null)
return;
ProcessingInstruction pi;
if (isL2
// && consumer.isUsingNamespaces ()
&& target.indexOf (':') != -1)
namespaceError (
"PI target name is namespace nonconformant: "
+ target);
if (inDTD)
return;
pi = document.createProcessingInstruction (target, data);
top.appendChild (pi);
}
/**
* Subclasses may overrride this method to provide a more efficient
* way to construct text nodes.
* Typically, copying the text into a single character array will
* be more efficient than doing that as well as allocating other
* needed for a String, including an internal StringBuffer.
* Those additional memory and CPU costs can be incurred later,
* if ever needed.
* Unfortunately the standard DOM factory APIs encourage those costs
* to be incurred early.
*/
protected Text createText (
boolean isCDATA,
char ch [],
int start,
int length
) {
String value = new String (ch, start, length);
if (isCDATA)
return document.createCDATASection (value);
else
return document.createTextNode (value);
}
// SAX1
public void characters (char ch [], int start, int length)
throws SAXException
{
// we can't create populated entity ref nodes using
// only public DOM APIs (they've got to be readonly
// at creation time)
if (currentEntity != null)
return;
Node lastChild = top.getLastChild ();
// merge consecutive text or CDATA nodes if appropriate.
if (lastChild instanceof Text) {
if (consumer.isHidingCDATA ()
// consecutive Text content ... always merge
|| (!inCDATA
&& !(lastChild instanceof CDATASection))
// consecutive CDATASection content ... don't
// merge between sections, only within them
|| (inCDATA && mergeCDATA
&& lastChild instanceof CDATASection)
) {
CharacterData last = (CharacterData) lastChild;
String value = new String (ch, start, length);
last.appendData (value);
return;
}
}
if (inCDATA && !consumer.isHidingCDATA ()) {
top.appendChild (createText (true, ch, start, length));
mergeCDATA = true;
} else
top.appendChild (createText (false, ch, start, length));
}
// SAX2
public void skippedEntity (String name)
throws SAXException
{
// this callback is useless except to report errors, since
// we can't know if the ref was in content, within an
// attribute, within a declaration ... only one of those
// cases supports more intelligent action than a panic.
fatal ("skipped entity: " + name, null);
}
// SAX2
public void startPrefixMapping (String prefix, String uri)
throws SAXException
{
// reconstruct "xmlns" attributes deleted by all
// SAX2 parsers without "namespace-prefixes" = true
if ("".equals (prefix))
attributes.addAttribute ("", "", "xmlns",
"CDATA", uri);
else
attributes.addAttribute ("", "", "xmlns:" + prefix,
"CDATA", uri);
recreatedAttrs = true;
}
// SAX2
public void endPrefixMapping (String prefix)
throws SAXException
{ }
// SAX2
public void startElement (
String uri,
String localName,
String qName,
Attributes atts
) throws SAXException
{
// we can't create populated entity ref nodes using
// only public DOM APIs (they've got to be readonly)
if (currentEntity != null)
return;
// parser discarded basic information; DOM tree isn't writable
// without massaging to assign prefixes to all nodes.
// the "NSFilter" class does that massaging.
if (qName.length () == 0)
qName = localName;
Element element;
int length = atts.getLength ();
if (!isL2) {
element = document.createElement (qName);
// first the explicit attributes ...
length = atts.getLength ();
for (int i = 0; i < length; i++)
element.setAttribute (atts.getQName (i),
atts.getValue (i));
// ... then any recreated ones (DOM deletes duplicates)
if (recreatedAttrs) {
recreatedAttrs = false;
length = attributes.getLength ();
for (int i = 0; i < length; i++)
element.setAttribute (attributes.getQName (i),
attributes.getValue (i));
attributes.clear ();
}
top.appendChild (element);
top = element;
return;
}
// For an L2 DOM when namespace use is enabled, use
// createElementNS/createAttributeNS except when
// (a) it's an element in the default namespace, or
// (b) it's an attribute with no prefix
String namespace;
if (localName.length () != 0)
namespace = (uri.length () == 0) ? null : uri;
else
namespace = getNamespace (getPrefix (qName), atts);
if (namespace == null)
element = document.createElement (qName);
else
element = document.createElementNS (namespace, qName);
populateAttributes (element, atts);
if (recreatedAttrs) {
recreatedAttrs = false;
// ... DOM deletes any duplicates
populateAttributes (element, attributes);
attributes.clear ();
}
top.appendChild (element);
top = element;
}
final static String xmlnsURI = "http://www.w3.org/2000/xmlns/";
private void populateAttributes (Element element, Attributes attrs)
throws SAXParseException
{
int length = attrs.getLength ();
for (int i = 0; i < length; i++) {
String type = attrs.getType (i);
String value = attrs.getValue (i);
String name = attrs.getQName (i);
String local = attrs.getLocalName (i);
String uri = attrs.getURI (i);
// parser discarded basic information, DOM tree isn't writable
if (name.length () == 0)
name = local;
// all attribute types other than these three may not
// contain scoped names... enumerated attributes get
// reported as NMTOKEN, except for NOTATION values
if (!("CDATA".equals (type)
|| "NMTOKEN".equals (type)
|| "NMTOKENS".equals (type))) {
if (value.indexOf (':') != -1) {
namespaceError (
"namespace nonconformant attribute value: "
+ "<" + element.getNodeName ()
+ " " + name + "='" + value + "' ...>");
}
}
// xmlns="" is legal (undoes default NS)
// xmlns:foo="" is illegal
String prefix = getPrefix (name);
String namespace;
if ("xmlns".equals (prefix)) {
if ("".equals (value))
namespaceError ("illegal null namespace decl, " + name);
namespace = xmlnsURI;
} else if ("xmlns".equals (name))
namespace = xmlnsURI;
else if (prefix == null)
namespace = null;
else if (!"".equals(uri) && uri.length () != 0)
namespace = uri;
else
namespace = getNamespace (prefix, attrs);
if (namespace == null)
element.setAttribute (name, value);
else
element.setAttributeNS (namespace, name, value);
}
}
private String getPrefix (String name)
{
int temp;
if ((temp = name.indexOf (':')) > 0)
return name.substring (0, temp);
return null;
}
// used with SAX1-level parser output
private String getNamespace (String prefix, Attributes attrs)
throws SAXParseException
{
String namespace;
String decl;
// defaulting
if (prefix == null) {
decl = "xmlns";
namespace = attrs.getValue (decl);
if ("".equals (namespace))
return null;
else if (namespace != null)
return namespace;
// "xmlns" is like a keyword
// ... according to the Namespace REC, but DOM L2 CR2+
// and Infoset violate that by assigning a namespace.
// that conflict is resolved elsewhere.
} else if ("xmlns".equals (prefix))
return null;
// "xml" prefix is fixed
else if ("xml".equals (prefix))
return "http://www.w3.org/XML/1998/namespace";
// otherwise, expect a declaration
else {
decl = "xmlns:" + prefix;
namespace = attrs.getValue (decl);
}
// if we found a local declaration, great
if (namespace != null)
return namespace;
// ELSE ... search up the tree we've been building
for (Node n = top;
n != null && n.getNodeType () != Node.DOCUMENT_NODE;
n = (Node) n.getParentNode ()) {
if (n.getNodeType () == Node.ENTITY_REFERENCE_NODE)
continue;
Element e = (Element) n;
Attr attr = e.getAttributeNode (decl);
if (attr != null)
return attr.getNodeValue ();
}
// see above re "xmlns" as keyword
if ("xmlns".equals (decl))
return null;
namespaceError ("Undeclared namespace prefix: " + prefix);
return null;
}
// SAX2
public void endElement (String uri, String localName, String qName)
throws SAXException
{
// we can't create populated entity ref nodes using
// only public DOM APIs (they've got to be readonly)
if (currentEntity != null)
return;
top = top.getParentNode ();
}
// SAX1 (mandatory reporting if validating)
public void ignorableWhitespace (char ch [], int start, int length)
throws SAXException
{
if (consumer.isHidingWhitespace ())
return;
characters (ch, start, length);
}
// SAX2 lexical event
public void startCDATA ()
throws SAXException
{
inCDATA = true;
// true except for the first fragment of a cdata section
mergeCDATA = false;
}
// SAX2 lexical event
public void endCDATA ()
throws SAXException
{
inCDATA = false;
}
// SAX2 lexical event
//
// this SAX2 callback merges two unrelated things:
// - Declaration of the root element type ... belongs with
// the other DTD declaration methods, NOT HERE.
// - IDs for the optional external subset ... belongs here
// with other lexical information.
//
// ...and it doesn't include the internal DTD subset, desired
// both to support DOM L2 and to enable "pass through" processing
//
public void startDTD (String name, String publicId, String SystemId)
throws SAXException
{
// need to filter out comments and PIs within the DTD
inDTD = true;
}
// SAX2 lexical event
public void endDTD ()
throws SAXException
{
inDTD = false;
}
// SAX2 lexical event
public void comment (char ch [], int start, int length)
throws SAXException
{
Node comment;
// we can't create populated entity ref nodes using
// only public DOM APIs (they've got to be readonly)
if (consumer.isHidingComments ()
|| inDTD
|| currentEntity != null)
return;
comment = document.createComment (new String (ch, start, length));
top.appendChild (comment);
}
/**
* May be overridden by subclasses to return true, indicating
* that entity reference nodes can be populated and then made
* read-only.
*/
public boolean canPopulateEntityRefs ()
{ return false; }
// SAX2 lexical event
public void startEntity (String name)
throws SAXException
{
// are we ignoring what would be contents of an
// entity ref, since we can't populate it?
if (currentEntity != null)
return;
// Are we hiding all entity boundaries?
if (consumer.isHidingReferences ())
return;
// SAX2 shows parameter entities; DOM hides them
if (name.charAt (0) == '%' || "[dtd]".equals (name))
return;
// Since we can't create a populated entity ref node in any
// standard way, we create an unpopulated one.
EntityReference ref = document.createEntityReference (name);
top.appendChild (ref);
top = ref;
// ... allowing subclasses to populate them
if (!canPopulateEntityRefs ())
currentEntity = name;
}
// SAX2 lexical event
public void endEntity (String name)
throws SAXException
{
if (name.charAt (0) == '%' || "[dtd]".equals (name))
return;
if (name.equals (currentEntity))
currentEntity = null;
if (!consumer.isHidingReferences ())
top = top.getParentNode ();
}
// SAX1 DTD event
public void notationDecl (
String name,
String publicId, String SystemId
) throws SAXException
{
/* IGNORE -- no public DOM API lets us store these
* into the doctype node
*/
}
// SAX1 DTD event
public void unparsedEntityDecl (
String name,
String publicId, String SystemId,
String notationName
) throws SAXException
{
/* IGNORE -- no public DOM API lets us store these
* into the doctype node
*/
}
// SAX2 declaration event
public void elementDecl (String name, String model)
throws SAXException
{
/* IGNORE -- no content model support in DOM L2 */
}
// SAX2 declaration event
public void attributeDecl (
String eName,
String aName,
String type,
String mode,
String value
) throws SAXException
{
/* IGNORE -- no attribute model support in DOM L2 */
}
// SAX2 declaration event
public void internalEntityDecl (String name, String value)
throws SAXException
{
/* IGNORE -- no public DOM API lets us store these
* into the doctype node
*/
}
// SAX2 declaration event
public void externalEntityDecl (
String name,
String publicId,
String SystemId
) throws SAXException
{
/* IGNORE -- no public DOM API lets us store these
* into the doctype node
*/
}
//
// These really should offer the option of nonfatal handling,
// like other validity errors, though that would cause major
// chaos in the DOM data structures. DOM is already spec'd
// to treat many of these as fatal, so this is consistent.
//
private void namespaceError (String description)
throws SAXParseException
{
SAXParseException err;
err = new SAXParseException (description, locator);
throw err;
}
}
}
@@ -0,0 +1,95 @@
/* EventConsumer.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., 59 Temple Place, Suite 330, Boston, MA
02111-1307 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.pipeline;
import org.xml.sax.*;
/**
* Collects the event consumption apparatus of a SAX pipeline stage.
* Consumers which permit some handlers or other characteristics to be
* configured will provide methods to support that configuration.
*
* <p> Two important categories of consumers include <em>filters</em>, which
* process events and pass them on to other consumers, and <em>terminus</em>
* (or <em>terminal</em>) stages, which don't pass events on. Filters are not
* necessarily derived from the {@link EventFilter} class, although that
* class can substantially simplify their construction by automating the
* most common activities.
*
* <p> Event consumers which follow certain conventions for the signatures
* of their constructors can be automatically assembled into pipelines
* by the {@link PipelineFactory} class.
*
* @author David Brownell
*/
public interface EventConsumer
{
/** Most stages process these core SAX callbacks. */
public ContentHandler getContentHandler ();
/** Few stages will use unparsed entities. */
public DTDHandler getDTDHandler ();
/**
* This method works like the SAX2 XMLReader method of the same name,
* and is used to retrieve the optional lexical and declaration handlers
* in a pipeline.
*
* @param id This is a URI identifying the type of property desired.
* @return The value of that property, if it is defined.
*
* @exception SAXNotRecognizedException Thrown if the particular
* pipeline stage does not understand the specified identifier.
*/
public Object getProperty (String id)
throws SAXNotRecognizedException;
/**
* This method provides a filter stage with a handler that abstracts
* presentation of warnings and both recoverable and fatal errors.
* Most pipeline stages should share a single policy and mechanism
* for such reports, since application components require consistency
* in such activities. Accordingly, typical responses to this method
* invocation involve saving the handler for use; filters will pass
* it on to any other consumers they use.
*
* @param handler encapsulates error handling policy for this stage
*/
public void setErrorHandler (ErrorHandler handler);
}
+809
View File
@@ -0,0 +1,809 @@
/* EventFilter.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., 59 Temple Place, Suite 330, Boston, MA
02111-1307 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.pipeline;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.xml.sax.*;
import org.xml.sax.ext.*;
import org.xml.sax.helpers.XMLFilterImpl;
import gnu.xml.aelfred2.ContentHandler2;
/**
* A customizable event consumer, used to assemble various kinds of filters
* using SAX handlers and an optional second consumer. It can be constructed
* in two ways: <ul>
*
* <li> To serve as a passthrough, sending all events to a second consumer.
* The second consumer may be identified through {@link #getNext}.
*
* <li> To serve as a dead end, with all handlers null;
* {@link #getNext} returns null.
*
* </ul>
*
* <p> Additionally, SAX handlers may be assigned, which completely replace
* the "upstream" view (through {@link EventConsumer}) of handlers, initially
* null or the "next" consumer provided to the constructor. To make
* it easier to build specialized filter classes, this class implements
* all the standard SAX consumer handlers, and those implementations
* delegate "downstream" to the consumer accessed by {@link #getNext}.
*
* <p> The simplest way to create a custom a filter class is to create a
* subclass which overrides one or more handler interface methods. The
* constructor for that subclass then registers itself as a handler for
* those interfaces using a call such as <em>setContentHandler(this)</em>,
* so the "upstream" view of event delivery is modified from the state
* established in the base class constructor. That way,
* the overridden methods intercept those event callbacks
* as they go "downstream", and
* all other event callbacks will pass events to any next consumer.
* Overridden methods may invoke superclass methods (perhaps after modifying
* parameters) if they wish to delegate such calls. Such subclasses
* should use {@link #getErrorHandler} to report errors using the
* common error reporting mechanism.
*
* <p> Another important technique is to construct a filter consisting
* of only a few specific types of handler. For example, one could easily
* prune out lexical events or various declarations by providing handlers
* which don't pass those events downstream, or by providing null handlers.
*
* <hr />
*
* <p> This may be viewed as the consumer oriented analogue of the SAX2
* {@link org.xml.sax.helpers.XMLFilterImpl XMLFilterImpl} class.
* Key differences include: <ul>
*
* <li> This fully separates consumer and producer roles: it
* does not implement the producer side <em>XMLReader</em> or
* <em>EntityResolver</em> interfaces, so it can only be used
* in "push" mode (it has no <em>parse()</em> methods).
*
* <li> "Extension" handlers are fully supported, enabling a
* richer set of application requirements.
* And it implements {@link EventConsumer}, which groups related
* consumer methods together, rather than leaving them separated.
*
* <li> The chaining which is visible is "downstream" to the next
* consumer, not "upstream" to the preceding producer.
* It supports "fan-in", where
* a consumer can be fed by several producers. (For "fan-out",
* see the {@link TeeConsumer} class.)
*
* <li> Event chaining is set up differently. It is intended to
* work "upstream" from terminus towards producer, during filter
* construction, as described above.
* This is part of an early binding model:
* events don't need to pass through stages which ignore them.
*
* <li> ErrorHandler support is separated, on the grounds that
* pipeline stages need to share the same error handling policy.
* For the same reason, error handler setup goes "downstream":
* when error handlers get set, they are passed to subsequent
* consumers.
*
* </ul>
*
* <p> The {@link #chainTo chainTo()} convenience routine supports chaining to
* an XMLFilterImpl, in its role as a limited functionality event
* consumer. Its event producer role ({@link XMLFilter}) is ignored.
*
* <hr />
*
* <p> The {@link #bind bind()} routine may be used associate event pipelines
* with any kind of {@link XMLReader} that will produce the events.
* Such pipelines don't necessarily need to have any members which are
* implemented using this class. That routine has some intelligence
* which supports automatic changes to parser feature flags, letting
* event piplines become largely independent of the particular feature
* sets of parsers.
*
* @author David Brownell
*/
public class EventFilter
implements EventConsumer, ContentHandler2, DTDHandler,
LexicalHandler, DeclHandler
{
// SAX handlers
private ContentHandler docHandler, docNext;
private DTDHandler dtdHandler, dtdNext;
private LexicalHandler lexHandler, lexNext;
private DeclHandler declHandler, declNext;
// and ideally, one more for the stuff SAX2 doesn't show
private Locator locator;
private EventConsumer next;
private ErrorHandler errHandler;
/** SAX2 URI prefix for standard feature flags. */
public static final String FEATURE_URI
= "http://xml.org/sax/features/";
/** SAX2 URI prefix for standard properties (mostly for handlers). */
public static final String PROPERTY_URI
= "http://xml.org/sax/properties/";
/** SAX2 property identifier for {@link DeclHandler} events */
public static final String DECL_HANDLER
= PROPERTY_URI + "declaration-handler";
/** SAX2 property identifier for {@link LexicalHandler} events */
public static final String LEXICAL_HANDLER
= PROPERTY_URI + "lexical-handler";
//
// These class objects will be null if the relevant class isn't linked.
// Small configurations (pJava and some kinds of embedded systems) need
// to facilitate smaller executables. So "instanceof" is undesirable
// when bind() sees if it can remove some stages.
//
// SECURITY NOTE: assuming all these classes are part of the same sealed
// package, there's no problem saving these in the instance of this class
// that's associated with "this" class loader. But that wouldn't be true
// for classes in another package.
//
private static boolean loaded;
private static Class nsClass;
private static Class validClass;
private static Class wfClass;
private static Class xincClass;
static ClassLoader getClassLoader ()
{
Method m = null;
try {
m = Thread.class.getMethod("getContextClassLoader", null);
} catch (NoSuchMethodException e) {
// Assume that we are running JDK 1.1, use the current ClassLoader
return EventFilter.class.getClassLoader();
}
try {
return (ClassLoader) m.invoke(Thread.currentThread(), null);
} catch (IllegalAccessException e) {
// assert(false)
throw new UnknownError(e.getMessage());
} catch (InvocationTargetException e) {
// assert(e.getTargetException() instanceof SecurityException)
throw new UnknownError(e.getMessage());
}
}
static Class loadClass (ClassLoader classLoader, String className)
{
try {
if (classLoader == null)
return Class.forName(className);
else
return classLoader.loadClass(className);
} catch (Exception e) {
return null;
}
}
static private void loadClasses ()
{
ClassLoader loader = getClassLoader ();
nsClass = loadClass (loader, "gnu.xml.pipeline.NSFilter");
validClass = loadClass (loader, "gnu.xml.pipeline.ValidationConsumer");
wfClass = loadClass (loader, "gnu.xml.pipeline.WellFormednessFilter");
xincClass = loadClass (loader, "gnu.xml.pipeline.XIncludeFilter");
loaded = true;
}
/**
* Binds the standard SAX2 handlers from the specified consumer
* pipeline to the specified producer. These handlers include the core
* {@link ContentHandler} and {@link DTDHandler}, plus the extension
* {@link DeclHandler} and {@link LexicalHandler}. Any additional
* application-specific handlers need to be bound separately.
* The {@link ErrorHandler} is handled differently: the producer's
* error handler is passed through to the consumer pipeline.
* The producer is told to include namespace prefix information if it
* can, since many pipeline stages need that Infoset information to
* work well.
*
* <p> At the head of the pipeline, certain standard event filters are
* recognized and handled specially. This facilitates construction
* of processing pipelines that work regardless of the capabilities
* of the XMLReader implementation in use; for example, it permits
* validating output of a {@link gnu.xml.util.DomParser}. <ul>
*
* <li> {@link NSFilter} will be removed if the producer can be
* told not to discard namespace data, using the "namespace-prefixes"
* feature flag.
*
* <li> {@link ValidationConsumer} will be removed if the producer
* can be told to validate, using the "validation" feature flag.
*
* <li> {@link WellFormednessFilter} is always removed, on the
* grounds that no XMLReader is permitted to producee malformed
* event streams and this would just be processing overhead.
*
* <li> {@link XIncludeFilter} stops the special handling, except
* that it's told about the "namespace-prefixes" feature of the
* event producer so that the event stream is internally consistent.
*
* <li> The first consumer which is not one of those classes stops
* such special handling. This means that if you want to force
* one of those filters to be used, you could just precede it with
* an instance of {@link EventFilter} configured as a pass-through.
* You might need to do that if you are using an {@link NSFilter}
* subclass to fix names found in attributes or character data.
*
* </ul>
*
* <p> Other than that, this method works with any kind of event consumer,
* not just event filters. Note that in all cases, the standard handlers
* are assigned; any previous handler assignments for the handler will
* be overridden.
*
* @param producer will deliver events to the specified consumer
* @param consumer pipeline supplying event handlers to be associated
* with the producer (may not be null)
*/
public static void bind (XMLReader producer, EventConsumer consumer)
{
Class klass = null;
boolean prefixes;
if (!loaded)
loadClasses ();
// DOM building, printing, layered validation, and other
// things don't work well when prefix info is discarded.
// Include it by default, whenever possible.
try {
producer.setFeature (FEATURE_URI + "namespace-prefixes",
true);
prefixes = true;
} catch (SAXException e) {
prefixes = false;
}
// NOTE: This loop doesn't use "instanceof", since that
// would prevent compiling/linking without those classes
// being present.
while (consumer != null) {
klass = consumer.getClass ();
// we might have already changed this problematic SAX2 default.
if (nsClass != null && nsClass.isAssignableFrom (klass)) {
if (!prefixes)
break;
consumer = ((EventFilter)consumer).getNext ();
// the parser _might_ do DTD validation by default ...
// if not, maybe we can change this setting.
} else if (validClass != null
&& validClass.isAssignableFrom (klass)) {
try {
producer.setFeature (FEATURE_URI + "validation",
true);
consumer = ((ValidationConsumer)consumer).getNext ();
} catch (SAXException e) {
break;
}
// parsers are required not to have such bugs
} else if (wfClass != null && wfClass.isAssignableFrom (klass)) {
consumer = ((WellFormednessFilter)consumer).getNext ();
// stop on the first pipeline stage we can't remove
} else
break;
if (consumer == null)
klass = null;
}
// the actual setting here doesn't matter as much
// as that producer and consumer agree
if (xincClass != null && klass != null
&& xincClass.isAssignableFrom (klass))
((XIncludeFilter)consumer).setSavingPrefixes (prefixes);
// Some SAX parsers can't handle null handlers -- bleech
DefaultHandler2 h = new DefaultHandler2 ();
if (consumer != null && consumer.getContentHandler () != null)
producer.setContentHandler (consumer.getContentHandler ());
else
producer.setContentHandler (h);
if (consumer != null && consumer.getDTDHandler () != null)
producer.setDTDHandler (consumer.getDTDHandler ());
else
producer.setDTDHandler (h);
try {
Object dh;
if (consumer != null)
dh = consumer.getProperty (DECL_HANDLER);
else
dh = null;
if (dh == null)
dh = h;
producer.setProperty (DECL_HANDLER, dh);
} catch (Exception e) { /* ignore */ }
try {
Object lh;
if (consumer != null)
lh = consumer.getProperty (LEXICAL_HANDLER);
else
lh = null;
if (lh == null)
lh = h;
producer.setProperty (LEXICAL_HANDLER, lh);
} catch (Exception e) { /* ignore */ }
// this binding goes the other way around
if (producer.getErrorHandler () == null)
producer.setErrorHandler (h);
if (consumer != null)
consumer.setErrorHandler (producer.getErrorHandler ());
}
/**
* Initializes all handlers to null.
*/
// constructor used by PipelineFactory
public EventFilter () { }
/**
* Handlers that are not otherwise set will default to those from
* the specified consumer, making it easy to pass events through.
* If the consumer is null, all handlers are initialzed to null.
*/
// constructor used by PipelineFactory
public EventFilter (EventConsumer consumer)
{
if (consumer == null)
return;
next = consumer;
// We delegate through the "xxNext" handlers, and
// report the "xxHandler" ones on our input side.
// Normally a subclass would both override handler
// methods and register itself as the "xxHandler".
docHandler = docNext = consumer.getContentHandler ();
dtdHandler = dtdNext = consumer.getDTDHandler ();
try {
declHandler = declNext = (DeclHandler)
consumer.getProperty (DECL_HANDLER);
} catch (SAXException e) { /* leave value null */ }
try {
lexHandler = lexNext = (LexicalHandler)
consumer.getProperty (LEXICAL_HANDLER);
} catch (SAXException e) { /* leave value null */ }
}
/**
* Treats the XMLFilterImpl as a limited functionality event consumer,
* by arranging to deliver events to it; this lets such classes be
* "wrapped" as pipeline stages.
*
* <p> <em>Upstream Event Setup:</em>
* If no handlers have been assigned to this EventFilter, then the
* handlers from specified XMLFilterImpl are returned from this
* {@link EventConsumer}: the XMLFilterImpl is just "wrapped".
* Otherwise the specified handlers will be returned.
*
* <p> <em>Downstream Event Setup:</em>
* Subclasses may chain event delivery to the specified XMLFilterImpl
* by invoking the appropiate superclass methods,
* as if their constructor passed a "next" EventConsumer to the
* constructor for this class.
* If this EventFilter has an ErrorHandler, it is assigned as
* the error handler for the XMLFilterImpl, just as would be
* done for a next stage implementing {@link EventConsumer}.
*
* @param next the next downstream component of the pipeline.
* @exception IllegalStateException if the "next" consumer has
* already been set through the constructor.
*/
public void chainTo (XMLFilterImpl next)
{
if (this.next != null)
throw new IllegalStateException ();
docNext = next.getContentHandler ();
if (docHandler == null)
docHandler = docNext;
dtdNext = next.getDTDHandler ();
if (dtdHandler == null)
dtdHandler = dtdNext;
try {
declNext = (DeclHandler) next.getProperty (DECL_HANDLER);
if (declHandler == null)
declHandler = declNext;
} catch (SAXException e) { /* leave value null */ }
try {
lexNext = (LexicalHandler) next.getProperty (LEXICAL_HANDLER);
if (lexHandler == null)
lexHandler = lexNext;
} catch (SAXException e) { /* leave value null */ }
if (errHandler != null)
next.setErrorHandler (errHandler);
}
/**
* Records the error handler that should be used by this stage, and
* passes it "downstream" to any subsequent stage.
*/
final public void setErrorHandler (ErrorHandler handler)
{
errHandler = handler;
if (next != null)
next.setErrorHandler (handler);
}
/**
* Returns the error handler assigned this filter stage, or null
* if no such assigment has been made.
*/
final public ErrorHandler getErrorHandler ()
{
return errHandler;
}
/**
* Returns the next event consumer in sequence; or null if there
* is no such handler.
*/
final public EventConsumer getNext ()
{ return next; }
/**
* Assigns the content handler to use; a null handler indicates
* that these events will not be forwarded.
* This overrides the previous settting for this handler, which was
* probably pointed to the next consumer by the base class constructor.
*/
final public void setContentHandler (ContentHandler h)
{
docHandler = h;
}
/** Returns the content handler being used. */
final public ContentHandler getContentHandler ()
{
return docHandler;
}
/**
* Assigns the DTD handler to use; a null handler indicates
* that these events will not be forwarded.
* This overrides the previous settting for this handler, which was
* probably pointed to the next consumer by the base class constructor.
*/
final public void setDTDHandler (DTDHandler h)
{ dtdHandler = h; }
/** Returns the dtd handler being used. */
final public DTDHandler getDTDHandler ()
{
return dtdHandler;
}
/**
* Stores the property, normally a handler; a null handler indicates
* that these events will not be forwarded.
* This overrides the previous handler settting, which was probably
* pointed to the next consumer by the base class constructor.
*/
final public void setProperty (String id, Object o)
throws SAXNotRecognizedException, SAXNotSupportedException
{
try {
Object value = getProperty (id);
if (value == o)
return;
if (DECL_HANDLER.equals (id)) {
declHandler = (DeclHandler) o;
return;
}
if (LEXICAL_HANDLER.equals (id)) {
lexHandler = (LexicalHandler) o;
return;
}
throw new SAXNotSupportedException (id);
} catch (ClassCastException e) {
throw new SAXNotSupportedException (id);
}
}
/** Retrieves a property of unknown intent (usually a handler) */
final public Object getProperty (String id)
throws SAXNotRecognizedException
{
if (DECL_HANDLER.equals (id))
return declHandler;
if (LEXICAL_HANDLER.equals (id))
return lexHandler;
throw new SAXNotRecognizedException (id);
}
/**
* Returns any locator provided to the next consumer, if this class
* (or a subclass) is handling {@link ContentHandler } events.
*/
public Locator getDocumentLocator ()
{ return locator; }
// CONTENT HANDLER DELEGATIONS
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void setDocumentLocator (Locator locator)
{
this.locator = locator;
if (docNext != null)
docNext.setDocumentLocator (locator);
}
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void startDocument () throws SAXException
{
if (docNext != null)
docNext.startDocument ();
}
public void xmlDecl(String version, String encoding, boolean standalone,
String inputEncoding)
throws SAXException
{
if (docNext != null && docNext instanceof ContentHandler2)
{
((ContentHandler2) docNext).xmlDecl(version, encoding, standalone,
inputEncoding);
}
}
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void skippedEntity (String name) throws SAXException
{
if (docNext != null)
docNext.skippedEntity (name);
}
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void processingInstruction (String target, String data)
throws SAXException
{
if (docNext != null)
docNext.processingInstruction (target, data);
}
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void characters (char ch [], int start, int length)
throws SAXException
{
if (docNext != null)
docNext.characters (ch, start, length);
}
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void ignorableWhitespace (char ch [], int start, int length)
throws SAXException
{
if (docNext != null)
docNext.ignorableWhitespace (ch, start, length);
}
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void startPrefixMapping (String prefix, String uri)
throws SAXException
{
if (docNext != null)
docNext.startPrefixMapping (prefix, uri);
}
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void startElement (
String uri, String localName,
String qName, Attributes atts
) throws SAXException
{
if (docNext != null)
docNext.startElement (uri, localName, qName, atts);
}
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void endElement (String uri, String localName, String qName)
throws SAXException
{
if (docNext != null)
docNext.endElement (uri, localName, qName);
}
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void endPrefixMapping (String prefix) throws SAXException
{
if (docNext != null)
docNext.endPrefixMapping (prefix);
}
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void endDocument () throws SAXException
{
if (docNext != null)
docNext.endDocument ();
locator = null;
}
// DTD HANDLER DELEGATIONS
/** <b>SAX1:</b> passes this callback to the next consumer, if any */
public void unparsedEntityDecl (
String name,
String publicId,
String systemId,
String notationName
) throws SAXException
{
if (dtdNext != null)
dtdNext.unparsedEntityDecl (name, publicId, systemId, notationName);
}
/** <b>SAX1:</b> passes this callback to the next consumer, if any */
public void notationDecl (String name, String publicId, String systemId)
throws SAXException
{
if (dtdNext != null)
dtdNext.notationDecl (name, publicId, systemId);
}
// LEXICAL HANDLER DELEGATIONS
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void startDTD (String name, String publicId, String systemId)
throws SAXException
{
if (lexNext != null)
lexNext.startDTD (name, publicId, systemId);
}
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void endDTD ()
throws SAXException
{
if (lexNext != null)
lexNext.endDTD ();
}
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void comment (char ch [], int start, int length)
throws SAXException
{
if (lexNext != null)
lexNext.comment (ch, start, length);
}
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void startCDATA ()
throws SAXException
{
if (lexNext != null)
lexNext.startCDATA ();
}
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void endCDATA ()
throws SAXException
{
if (lexNext != null)
lexNext.endCDATA ();
}
/**
* <b>SAX2:</b> passes this callback to the next consumer, if any.
*/
public void startEntity (String name)
throws SAXException
{
if (lexNext != null)
lexNext.startEntity (name);
}
/**
* <b>SAX2:</b> passes this callback to the next consumer, if any.
*/
public void endEntity (String name)
throws SAXException
{
if (lexNext != null)
lexNext.endEntity (name);
}
// DECLARATION HANDLER DELEGATIONS
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void elementDecl (String name, String model)
throws SAXException
{
if (declNext != null)
declNext.elementDecl (name, model);
}
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void attributeDecl (String eName, String aName,
String type, String mode, String value)
throws SAXException
{
if (declNext != null)
declNext.attributeDecl (eName, aName, type, mode, value);
}
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void externalEntityDecl (String name,
String publicId, String systemId)
throws SAXException
{
if (declNext != null)
declNext.externalEntityDecl (name, publicId, systemId);
}
/** <b>SAX2:</b> passes this callback to the next consumer, if any */
public void internalEntityDecl (String name, String value)
throws SAXException
{
if (declNext != null)
declNext.internalEntityDecl (name, value);
}
}
+243
View File
@@ -0,0 +1,243 @@
/* LinkFilter.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., 59 Temple Place, Suite 330, Boston, MA
02111-1307 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.pipeline;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Vector;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
/**
* Pipeline filter to remember XHTML links found in a document,
* so they can later be crawled. Fragments are not counted, and duplicates
* are ignored. Callers are responsible for filtering out URLs they aren't
* interested in. Events are passed through unmodified.
*
* <p> Input MUST include a setDocumentLocator() call, as it's used to
* resolve relative links in the absence of a "base" element. Input MUST
* also include namespace identifiers, since it is the XHTML namespace
* identifier which is used to identify the relevant elements.
*
* <p><em>FIXME:</em> handle xml:base attribute ... in association with
* a stack of base URIs. Similarly, recognize/support XLink data.
*
* @author David Brownell
*/
public class LinkFilter extends EventFilter
{
// for storing URIs
private Vector vector = new Vector ();
// struct for "full" link record (tbd)
// these for troubleshooting original source:
// original uri
// uri as resolved (base, relative, etc)
// URI of originating doc
// line #
// original element + attrs (img src, desc, etc)
// XLink model of the link ... for inter-site pairups ?
private String baseURI;
private boolean siteRestricted = false;
//
// XXX leverage blacklist info (like robots.txt)
//
// XXX constructor w/param ... pipeline for sending link data
// probably XHTML --> XLink, providing info as sketched above
//
/**
* Constructs a new event filter, which collects links in private data
* structure for later enumeration.
*/
// constructor used by PipelineFactory
public LinkFilter ()
{
super.setContentHandler (this);
}
/**
* Constructs a new event filter, which collects links in private data
* structure for later enumeration and passes all events, unmodified,
* to the next consumer.
*/
// constructor used by PipelineFactory
public LinkFilter (EventConsumer next)
{
super (next);
super.setContentHandler (this);
}
/**
* Returns an enumeration of the links found since the filter
* was constructed, or since removeAllLinks() was called.
*
* @return enumeration of strings.
*/
public Enumeration getLinks ()
{
return vector.elements ();
}
/**
* Removes records about all links reported to the event
* stream, as if the filter were newly created.
*/
public void removeAllLinks ()
{
vector = new Vector ();
}
/**
* Collects URIs for (X)HTML content from elements which hold them.
*/
public void startElement (
String uri,
String localName,
String qName,
Attributes atts
) throws SAXException
{
String link;
// Recognize XHTML links.
if ("http://www.w3.org/1999/xhtml".equals (uri)) {
if ("a".equals (localName) || "base".equals (localName)
|| "area".equals (localName))
link = atts.getValue ("href");
else if ("iframe".equals (localName) || "frame".equals (localName))
link = atts.getValue ("src");
else if ("blockquote".equals (localName) || "q".equals (localName)
|| "ins".equals (localName) || "del".equals (localName))
link = atts.getValue ("cite");
else
link = null;
link = maybeAddLink (link);
// "base" modifies designated baseURI
if ("base".equals (localName) && link != null)
baseURI = link;
if ("iframe".equals (localName) || "img".equals (localName))
maybeAddLink (atts.getValue ("longdesc"));
}
super.startElement (uri, localName, qName, atts);
}
private String maybeAddLink (String link)
{
int index;
// ignore empty links and fragments inside docs
if (link == null)
return null;
if ((index = link.indexOf ("#")) >= 0)
link = link.substring (0, index);
if (link.equals (""))
return null;
try {
// get the real URI
URL base = new URL ((baseURI != null)
? baseURI
: getDocumentLocator ().getSystemId ());
URL url = new URL (base, link);
link = url.toString ();
// ignore duplicates
if (vector.contains (link))
return link;
// other than what "base" does, stick to original site:
if (siteRestricted) {
// don't switch protocols
if (!base.getProtocol ().equals (url.getProtocol ()))
return link;
// don't switch servers
if (base.getHost () != null
&& !base.getHost ().equals (url.getHost ()))
return link;
}
vector.addElement (link);
return link;
} catch (IOException e) {
// bad URLs we don't want
}
return null;
}
/**
* Reports an error if no Locator has been made available.
*/
public void startDocument ()
throws SAXException
{
if (getDocumentLocator () == null)
throw new SAXException ("no Locator!");
}
/**
* Forgets about any base URI information that may be recorded.
* Applications will often want to call removeAllLinks(), likely
* after examining the links which were reported.
*/
public void endDocument ()
throws SAXException
{
baseURI = null;
super.endDocument ();
}
}
+340
View File
@@ -0,0 +1,340 @@
/* NSFilter.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., 59 Temple Place, Suite 330, Boston, MA
02111-1307 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.pipeline;
import java.util.EmptyStackException;
import java.util.Enumeration;
import java.util.Stack;
import org.xml.sax.*;
import org.xml.sax.ext.*;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.NamespaceSupport;
/**
* This filter ensures that element and attribute names are properly prefixed,
* and that such prefixes are declared. Such data is critical for operations
* like writing XML text, and validating against DTDs: names or their prefixes
* may have been discarded, although they are essential to the exchange of
* information using XML. There are various common ways that such data
* gets discarded: <ul>
*
* <li> By default, SAX2 parsers must discard the "xmlns*"
* attributes, and may also choose not to report properly prefixed
* names for elements or attributes. (Some parsers may support
* changing the <em>namespace-prefixes</em> value from the default
* to <em>true</em>, effectively eliminating the need to use this
* filter on their output.)
*
* <li> When event streams are generated from a DOM tree, they may
* have never have had prefixes or declarations for namespaces; or
* the existing prefixes or declarations may have been invalidated
* by structural modifications to that DOM tree.
*
* <li> Other software writing SAX event streams won't necessarily
* be worrying about prefix management, and so they will need to
* have a transparent solution for managing them.
*
* </ul>
*
* <p> This filter uses a heuristic to choose the prefix to assign to any
* particular name which wasn't already corectly prefixed. The associated
* namespace will be correct, and the prefix will be declared. Original
* structures facilitating text editing, such as conventions about use of
* mnemonic prefix names or the scoping of prefixes, can't always be
* reconstructed after they are discarded, as strongly encouraged by the
* current SAX2 defaults.
*
* <p> Note that this can't possibly know whether values inside attribute
* value or document content involve prefixed names. If your application
* requires using prefixed names in such locations you'll need to add some
* appropriate logic (perhaps adding additional heuristics in a subclass).
*
* @author David Brownell
*/
public class NSFilter extends EventFilter
{
private NamespaceSupport nsStack = new NamespaceSupport ();
private Stack elementStack = new Stack ();
private boolean pushedContext;
private String nsTemp [] = new String [3];
private AttributesImpl attributes = new AttributesImpl ();
private boolean usedDefault;
// gensymmed prefixes use this root name
private static final String prefixRoot = "prefix-";
/**
* Passes events through to the specified consumer, after first
* processing them.
*
* @param next the next event consumer to receive events.
*/
// constructor used by PipelineFactory
public NSFilter (EventConsumer next)
{
super (next);
setContentHandler (this);
}
private void fatalError (String message)
throws SAXException
{
SAXParseException e;
ErrorHandler handler = getErrorHandler ();
Locator locator = getDocumentLocator ();
if (locator == null)
e = new SAXParseException (message, null, null, -1, -1);
else
e = new SAXParseException (message, locator);
if (handler != null)
handler.fatalError (e);
throw e;
}
public void startDocument () throws SAXException
{
elementStack.removeAllElements ();
nsStack.reset ();
pushedContext = false;
super.startDocument ();
}
/**
* This call is not passed to the next consumer in the chain.
* Prefix declarations and scopes are only exposed in the form
* of attributes; this callback just records a declaration that
* will be exposed as an attribute.
*/
public void startPrefixMapping (String prefix, String uri)
throws SAXException
{
if (pushedContext == false) {
nsStack.pushContext ();
pushedContext = true;
}
// this check is awkward, but the paranoia prevents big trouble
for (Enumeration e = nsStack.getDeclaredPrefixes ();
e.hasMoreElements ();
/* NOP */ ) {
String declared = (String) e.nextElement ();
if (!declared.equals (prefix))
continue;
if (uri.equals (nsStack.getURI (prefix)))
return;
fatalError ("inconsistent binding for prefix '" + prefix
+ "' ... " + uri + " (was " + nsStack.getURI (prefix) + ")");
}
if (!nsStack.declarePrefix (prefix, uri))
fatalError ("illegal prefix declared: " + prefix);
}
private String fixName (String ns, String l, String name, boolean isAttr)
throws SAXException
{
if ("".equals (name) || name == null) {
name = l;
if ("".equals (name) || name == null)
fatalError ("empty/null name");
}
// can we correctly process the name as-is?
// handles "element scope" attribute names here.
if (nsStack.processName (name, nsTemp, isAttr) != null
&& nsTemp [0].equals (ns)
) {
return nsTemp [2];
}
// nope, gotta modify the name or declare a default mapping
int temp;
// get rid of any current prefix
if ((temp = name.indexOf (':')) >= 0) {
name = name.substring (temp + 1);
// ... maybe that's enough (use/prefer default namespace) ...
if (!isAttr && nsStack.processName (name, nsTemp, false) != null
&& nsTemp [0].equals (ns)
) {
return nsTemp [2];
}
}
// must we define and use the default/undefined prefix?
if ("".equals (ns)) {
if (isAttr)
fatalError ("processName bug");
if (attributes.getIndex ("xmlns") != -1)
fatalError ("need to undefine default NS, but it's bound: "
+ attributes.getValue ("xmlns"));
nsStack.declarePrefix ("", "");
attributes.addAttribute ("", "", "xmlns", "CDATA", "");
return name;
}
// is there at least one non-null prefix we can use?
for (Enumeration e = nsStack.getDeclaredPrefixes ();
e.hasMoreElements ();
/* NOP */) {
String prefix = (String) e.nextElement ();
String uri = nsStack.getURI (prefix);
if (uri == null || !uri.equals (ns))
continue;
return prefix + ":" + name;
}
// no such luck. create a prefix name, declare it, use it.
for (temp = 0; temp >= 0; temp++) {
String prefix = prefixRoot + temp;
if (nsStack.getURI (prefix) == null) {
nsStack.declarePrefix (prefix, ns);
attributes.addAttribute ("", "", "xmlns:" + prefix,
"CDATA", ns);
return prefix + ":" + name;
}
}
fatalError ("too many prefixes genned");
// NOTREACHED
return null;
}
public void startElement (
String uri, String localName,
String qName, Attributes atts
) throws SAXException
{
if (!pushedContext)
nsStack.pushContext ();
pushedContext = false;
// make sure we have all NS declarations handy before we start
int length = atts.getLength ();
for (int i = 0; i < length; i++) {
String aName = atts.getQName (i);
if (!aName.startsWith ("xmlns"))
continue;
String prefix;
if ("xmlns".equals (aName))
prefix = "";
else if (aName.indexOf (':') == 5)
prefix = aName.substring (6);
else // "xmlnsfoo" etc.
continue;
startPrefixMapping (prefix, atts.getValue (i));
}
// put namespace decls at the start of our regenned attlist
attributes.clear ();
for (Enumeration e = nsStack.getDeclaredPrefixes ();
e.hasMoreElements ();
/* NOP */) {
String prefix = (String) e.nextElement ();
attributes.addAttribute ("", "",
("".equals (prefix)
? "xmlns"
: "xmlns:" + prefix),
"CDATA",
nsStack.getURI (prefix));
}
// name fixups: element, then attributes.
// fixName may declare a new prefix or, for the element,
// redeclare the default (if element name needs it).
qName = fixName (uri, localName, qName, false);
for (int i = 0; i < length; i++) {
String aName = atts.getQName (i);
String aNS = atts.getURI (i);
String aLocal = atts.getLocalName (i);
String aType = atts.getType (i);
String aValue = atts.getValue (i);
if (aName.startsWith ("xmlns"))
continue;
aName = fixName (aNS, aLocal, aName, true);
attributes.addAttribute (aNS, aLocal, aName, aType, aValue);
}
elementStack.push (qName);
// pass event along, with cleaned-up names and decls.
super.startElement (uri, localName, qName, attributes);
}
public void endElement (String uri, String localName, String qName)
throws SAXException
{
nsStack.popContext ();
qName = (String) elementStack.pop ();
super.endElement (uri, localName, qName);
}
/**
* This call is not passed to the next consumer in the chain.
* Prefix declarations and scopes are only exposed in their
* attribute form.
*/
public void endPrefixMapping (String prefix)
throws SAXException
{ }
public void endDocument () throws SAXException
{
elementStack.removeAllElements ();
nsStack.reset ();
super.endDocument ();
}
}
@@ -0,0 +1,723 @@
/* PipelineFactory.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., 59 Temple Place, Suite 330, Boston, MA
02111-1307 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.pipeline;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.Constructor;
import java.util.StringTokenizer;
import org.xml.sax.*;
import org.xml.sax.ext.*;
/**
* This provides static factory methods for creating simple event pipelines.
* These pipelines are specified by strings, suitable for passing on
* command lines or embedding in element attributes. For example, one way
* to write a pipeline that restores namespace syntax, validates (stopping
* the pipeline on validity errors) and then writes valid data to standard
* output is this: <pre>
* nsfix | validate | write ( stdout )</pre>
*
* <p> In this syntax, the tokens are always separated by whitespace, and each
* stage of the pipeline may optionally have a parameter (which can be a
* pipeline) in parentheses. Interior stages are called filters, and the
* rightmost end of a pipeline is called a terminus.
*
* <p> Stages are usually implemented by a single class, which may not be
* able to act as both a filter and a terminus; but any terminus can be
* automatically turned into a filter, through use of a {@link TeeConsumer}.
* The stage identifiers are either class names, or are one of the following
* short identifiers built into this class. (Most of these identifiers are
* no more than aliases for classes.) The built-in identifiers include:</p>
<table border="1" cellpadding="3" cellspacing="0">
<tr bgcolor="#ccccff" class="TableHeadingColor">
<th align="center" width="5%">Stage</th>
<th align="center" width="9%">Parameter</th>
<th align="center" width="1%">Terminus</th>
<th align="center">Description</th>
</tr>
<tr valign="top" align="center">
<td><a href="../dom/Consumer.html">dom</a></td>
<td><em>none</em></td>
<td> yes </td>
<td align="left"> Applications code can access a DOM Document built
from the input event stream. When used as a filter, this buffers
data up to an <em>endDocument</em> call, and then uses a DOM parser
to report everything that has been recorded (which can easily be
less than what was reported to it). </td>
</tr>
<tr valign="top" align="center">
<td><a href="NSFilter.html">nsfix</a></td>
<td><em>none</em></td>
<td>no</td>
<td align="left">This stage ensures that the XML element and attribute
names in its output use namespace prefixes and declarations correctly.
That is, so that they match the "Namespace plus LocalName" naming data
with which each XML element and attribute is already associated. </td>
</tr>
<tr valign="top" align="center">
<td><a href="EventFilter.html">null</a></td>
<td><em>none</em></td>
<td>yes</td>
<td align="left">This stage ignores all input event data.</td>
</tr>
<tr valign="top" align="center">
<td><a href="CallFilter.html">server</a></td>
<td><em>required</em><br> server URL </td>
<td>no</td>
<td align="left">Sends its input as XML request to a remote server,
normally a web application server using the HTTP or HTTPS protocols.
The output of this stage is the parsed response from that server.</td>
</tr>
<tr valign="top" align="center">
<td><a href="TeeConsumer.html">tee</a></td>
<td><em>required</em><br> first pipeline</td>
<td>no</td>
<td align="left">This sends its events down two paths; its parameter
is a pipeline descriptor for the first path, and the second path
is the output of this stage.</td>
</tr>
<tr valign="top" align="center">
<td><a href="ValidationConsumer.html">validate</a></td>
<td><em>none</em></td>
<td>yes</td>
<td align="left">This checks for validity errors, and reports them
through its error handler. The input must include declaration events
and some lexical events. </td>
</tr>
<tr valign="top" align="center">
<td><a href="WellFormednessFilter.html">wf</a></td>
<td><em>none</em></td>
<td>yes</td>
<td align="left"> This class provides some basic "well formedness"
tests on the input event stream, and reports a fatal error if any
of them fail. One example: start/end calls for elements must match.
No SAX parser is permitted to produce malformed output, but other
components can easily do so.</td>
</tr>
<tr valign="top" align="center">
<td>write</td>
<td><em>required</em><br> "stdout", "stderr", or filename</td>
<td>yes</td>
<td align="left"> Writes its input to the specified output, as pretty
printed XML text encoded using UTF-8. Input events must be well
formed and "namespace fixed", else the output won't be XML (or possibly
namespace) conformant. The symbolic names represent
<em>System.out</em> and <em>System.err</em> respectively; names must
correspond to files which don't yet exist.</td>
</tr>
<tr valign="top" align="center">
<td>xhtml</td>
<td><em>required</em><br> "stdout", "stderr", or filename</td>
<td>yes</td>
<td align="left"> Like <em>write</em> (above), except that XHTML rules
are followed. The XHTML 1.0 Transitional document type is declared,
and only ASCII characters are written (for interoperability). Other
characters are written as entity or character references; the text is
pretty printed.</td>
</tr>
<tr valign="top" align="center">
<td><a href="XIncludeFilter.html">xinclude</a></td>
<td><em>none</em></td>
<td>no</td>
<td align="left">This stage handles XInclude processing.
This is like entity inclusion, except that the included content
is declared in-line rather than in the DTD at the beginning of
a document.
</td>
</tr>
<tr valign="top" align="center">
<td><a href="XsltFilter.html">xslt</a></td>
<td><em>required</em><br> XSLT stylesheet URI</td>
<td>no</td>
<td align="left">This stage handles XSLT transformation
according to a stylesheet.
The implementation of the transformation may not actually
stream data, although if such an XSLT engine is in use
then that can happen.
</td>
</tr>
</table>
* <p> Note that {@link EventFilter#bind} can automatically eliminate
* some filters by setting SAX2 parser features appropriately. This means
* that you can routinely put filters like "nsfix", "validate", or "wf" at the
* front of a pipeline (for components that need inputs conditioned to match
* that level of correctness), and know that it won't actually be used unless
* it's absolutely necessary.
*
* @author David Brownell
*/
public class PipelineFactory
{
/**
* Creates a simple pipeline according to the description string passed in.
*/
public static EventConsumer createPipeline (String description)
throws IOException
{
return createPipeline (description, null);
}
/**
* Extends an existing pipeline by prepending the filter pipeline to the
* specified consumer. Some pipelines need more customization than can
* be done through this simplified syntax. When they are set up with
* direct API calls, use this method to merge more complex pipeline
* segments with easily configured ones.
*/
public static EventConsumer createPipeline (
String description,
EventConsumer next
) throws IOException
{
// tokens are (for now) what's separated by whitespace;
// very easy to parse, but IDs never have spaces.
StringTokenizer tokenizer;
String tokens [];
tokenizer = new StringTokenizer (description);
tokens = new String [tokenizer.countTokens ()];
for (int i = 0; i < tokens.length; i++)
tokens [i] = tokenizer.nextToken ();
PipelineFactory factory = new PipelineFactory ();
Pipeline pipeline = factory.parsePipeline (tokens, next);
return pipeline.createPipeline ();
}
private PipelineFactory () { /* NYET */ }
/**
* Extends an existing pipeline by prepending a pre-tokenized filter
* pipeline to the specified consumer. Tokens are class names (or the
* predefined aliases) left and right parenthesis, and the vertical bar.
*/
public static EventConsumer createPipeline (
String tokens [],
EventConsumer next
) throws IOException
{
PipelineFactory factory = new PipelineFactory ();
Pipeline pipeline = factory.parsePipeline (tokens, next);
return pipeline.createPipeline ();
}
private String tokens [];
private int index;
private Pipeline parsePipeline (String toks [], EventConsumer next)
{
tokens = toks;
index = 0;
Pipeline retval = parsePipeline (next);
if (index != toks.length)
throw new ArrayIndexOutOfBoundsException (
"extra token: " + tokens [index]);
return retval;
}
// pipeline ::= stage | stage '|' pipeline
private Pipeline parsePipeline (EventConsumer next)
{
Pipeline retval = new Pipeline (parseStage ());
// minimal pipelines: "stage" and "... | id"
if (index > (tokens.length - 2)
|| !"|".equals (tokens [index])
) {
retval.next = next;
return retval;
}
index++;
retval.rest = parsePipeline (next);
return retval;
}
// stage ::= id | id '(' pipeline ')'
private Stage parseStage ()
{
Stage retval = new Stage (tokens [index++]);
// minimal stages: "id" and "id ( id )"
if (index > (tokens.length - 2)
|| !"(".equals (tokens [index]) /*)*/
)
return retval;
index++;
retval.param = parsePipeline (null);
if (index >= tokens.length)
throw new ArrayIndexOutOfBoundsException (
"missing right paren");
if (/*(*/ !")".equals (tokens [index++]))
throw new ArrayIndexOutOfBoundsException (
"required right paren, not: " + tokens [index - 1]);
return retval;
}
//
// these classes obey the conventions for constructors, so they're
// only built in to this table of shortnames
//
// - filter (one or two types of arglist)
// * last constructor is 'next' element
// * optional (first) string parameter
//
// - terminus (one or types of arglist)
// * optional (only) string parameter
//
// terminus stages are transformed into filters if needed, by
// creating a "tee". filter stages aren't turned to terminus
// stages though; either eliminate such stages, or add some
// terminus explicitly.
//
private static final String builtinStages [][] = {
{ "dom", "gnu.xml.dom.Consumer" },
{ "nsfix", "gnu.xml.pipeline.NSFilter" },
{ "null", "gnu.xml.pipeline.EventFilter" },
{ "server", "gnu.xml.pipeline.CallFilter" },
{ "tee", "gnu.xml.pipeline.TeeConsumer" },
{ "validate", "gnu.xml.pipeline.ValidationConsumer" },
{ "wf", "gnu.xml.pipeline.WellFormednessFilter" },
{ "xinclude", "gnu.xml.pipeline.XIncludeFilter" },
{ "xslt", "gnu.xml.pipeline.XsltFilter" },
// XXX want: option for validate, to preload external part of a DTD
// xhtml, write ... nyet generic-ready
};
private static class Stage
{
String id;
Pipeline param;
Stage (String name)
{ id = name; }
public String toString ()
{
if (param == null)
return id;
return id + " ( " + param + " )";
}
private void fail (String message)
throws IOException
{
throw new IOException ("in '" + id
+ "' stage of pipeline, " + message);
}
EventConsumer createStage (EventConsumer next)
throws IOException
{
String name = id;
// most builtins are just class aliases
for (int i = 0; i < builtinStages.length; i++) {
if (id.equals (builtinStages [i][0])) {
name = builtinStages [i][1];
break;
}
}
// Save output as XML or XHTML text
if ("write".equals (name) || "xhtml".equals (name)) {
String filename;
boolean isXhtml = "xhtml".equals (name);
OutputStream out = null;
TextConsumer consumer;
if (param == null)
fail ("parameter is required");
filename = param.toString ();
if ("stdout".equals (filename))
out = System.out;
else if ("stderr".equals (filename))
out = System.err;
else {
File f = new File (filename);
/*
if (!f.isAbsolute ())
fail ("require absolute file paths");
*/
if (f.exists ())
fail ("file already exists: " + f.getName ());
// XXX this races against the existence test
out = new FileOutputStream (f);
}
if (!isXhtml)
consumer = new TextConsumer (out);
else
consumer = new TextConsumer (
new OutputStreamWriter (out, "8859_1"),
true);
consumer.setPrettyPrinting (true);
if (next == null)
return consumer;
return new TeeConsumer (consumer, next);
} else {
//
// Here go all the builtins that are just aliases for
// classes, and all stage IDs that started out as such
// class names. The following logic relies on several
// documented conventions for constructor invocation.
//
String msg = null;
try {
Class klass = Class.forName (name);
Class argTypes [] = null;
Constructor constructor = null;
boolean filter = false;
Object params [] = null;
Object obj = null;
// do we need a filter stage?
if (next != null) {
// "next" consumer is always passed, with
// or without the optional string param
if (param == null) {
argTypes = new Class [1];
argTypes [0] = EventConsumer.class;
params = new Object [1];
params [0] = next;
msg = "no-param filter";
} else {
argTypes = new Class [2];
argTypes [0] = String.class;
argTypes [1] = EventConsumer.class;
params = new Object [2];
params [0] = param.toString ();
params [1] = next;
msg = "one-param filter";
}
try {
constructor = klass.getConstructor (argTypes);
} catch (NoSuchMethodException e) {
// try creating a filter from a
// terminus and a tee
filter = true;
msg += " built from ";
}
}
// build from a terminus stage, with or
// without the optional string param
if (constructor == null) {
String tmp;
if (param == null) {
argTypes = new Class [0];
params = new Object [0];
tmp = "no-param terminus";
} else {
argTypes = new Class [1];
argTypes [0] = String.class;
params = new Object [1];
params [0] = param.toString ();
tmp = "one-param terminus";
}
if (msg == null)
msg = tmp;
else
msg += tmp;
constructor = klass.getConstructor (argTypes);
// NOT creating terminus by dead-ending
// filters ... users should think about
// that one, something's likely wrong
}
obj = constructor.newInstance (params);
// return EventConsumers directly, perhaps after
// turning them into a filter
if (obj instanceof EventConsumer) {
if (filter)
return new TeeConsumer ((EventConsumer) obj, next);
return (EventConsumer) obj;
}
// if it's not a handler, it's an error
// we can wrap handlers in a filter
EventFilter retval = new EventFilter ();
boolean updated = false;
if (obj instanceof ContentHandler) {
retval.setContentHandler ((ContentHandler) obj);
updated = true;
}
if (obj instanceof DTDHandler) {
retval.setDTDHandler ((DTDHandler) obj);
updated = true;
}
if (obj instanceof LexicalHandler) {
retval.setProperty (
EventFilter.PROPERTY_URI + "lexical-handler",
obj);
updated = true;
}
if (obj instanceof DeclHandler) {
retval.setProperty (
EventFilter.PROPERTY_URI + "declaration-handler",
obj);
updated = true;
}
if (!updated)
fail ("class is neither Consumer nor Handler");
if (filter)
return new TeeConsumer (retval, next);
return retval;
} catch (IOException e) {
throw e;
} catch (NoSuchMethodException e) {
fail (name + " constructor missing -- " + msg);
} catch (ClassNotFoundException e) {
fail (name + " class not found");
} catch (Exception e) {
// e.printStackTrace ();
fail ("stage not available: " + e.getMessage ());
}
}
// NOTREACHED
return null;
}
}
private static class Pipeline
{
Stage stage;
// rest may be null
Pipeline rest;
EventConsumer next;
Pipeline (Stage s)
{ stage = s; }
public String toString ()
{
if (rest == null && next == null)
return stage.toString ();
if (rest != null)
return stage + " | " + rest;
throw new IllegalArgumentException ("next");
}
EventConsumer createPipeline ()
throws IOException
{
if (next == null) {
if (rest == null)
next = stage.createStage (null);
else
next = stage.createStage (rest.createPipeline ());
}
return next;
}
}
/*
public static void main (String argv [])
{
try {
// three basic terminus cases
createPipeline ("null");
createPipeline ("validate");
createPipeline ("write ( stdout )");
// four basic filters
createPipeline ("nsfix | write ( stderr )");
createPipeline ("wf | null");
createPipeline ("null | null");
createPipeline (
"call ( http://www.example.com/services/xml-1a ) | xhtml ( stdout )");
// tee junctions
createPipeline ("tee ( validate ) | write ( stdout )");
createPipeline ("tee ( nsfix | write ( stdout ) ) | validate");
// longer pipeline
createPipeline ("nsfix | tee ( validate ) | write ( stdout )");
createPipeline (
"null | wf | nsfix | tee ( validate ) | write ( stdout )");
// try some parsing error cases
try {
createPipeline ("null ("); // extra token '('
System.err.println ("** didn't report error");
} catch (Exception e) {
System.err.println ("== err: " + e.getMessage ()); }
try {
createPipeline ("nsfix |"); // extra token '|'
System.err.println ("** didn't report error");
} catch (Exception e) {
System.err.println ("== err: " + e.getMessage ()); }
try {
createPipeline ("xhtml ( foo"); // missing right paren
System.err.println ("** didn't report error");
} catch (Exception e) {
System.err.println ("== err: " + e.getMessage ()); }
try {
createPipeline ("xhtml ( foo bar"); // required right paren
System.err.println ("** didn't report error");
} catch (Exception e) {
System.err.println ("== err: " + e.getMessage ()); }
try {
createPipeline ("tee ( nsfix | validate");// missing right paren
System.err.println ("** didn't report error");
} catch (Exception e) {
System.err.println ("== err: " + e.getMessage ()); }
// try some construction error cases
try {
createPipeline ("call"); // missing param
System.err.println ("** didn't report error");
} catch (Exception e) {
System.err.println ("== err: " + e.getMessage ()); }
try {
createPipeline ("call ( foobar )"); // broken param
System.err.println ("** didn't report error");
} catch (Exception e) {
System.err.println ("== err: " + e.getMessage ()); }
try {
createPipeline ("nsfix ( foobar )"); // illegal param
System.err.println ("** didn't report error");
} catch (Exception e) {
System.err.println ("== err: " + e.getMessage ()); }
try {
createPipeline ("null ( foobar )"); // illegal param
System.err.println ("** didn't report error");
} catch (Exception e) {
System.err.println ("== err: " + e.getMessage ()); }
try {
createPipeline ("wf ( foobar )"); // illegal param
System.err.println ("** didn't report error");
} catch (Exception e) {
System.err.println ("== err: " + e.getMessage ()); }
try {
createPipeline ("xhtml ( foobar.html )");
new File ("foobar.html").delete ();
// now supported
} catch (Exception e) {
System.err.println ("** err: " + e.getMessage ()); }
try {
createPipeline ("xhtml"); // missing param
System.err.println ("** didn't report error");
} catch (Exception e) {
System.err.println ("== err: " + e.getMessage ()); }
try {
createPipeline ("write ( stdout ) | null"); // nonterminal
System.err.println ("** didn't report error");
} catch (Exception e) {
System.err.println ("== err: " + e.getMessage ()); }
try {
createPipeline ("validate | null");
// now supported
} catch (Exception e) {
System.err.println ("** err: " + e.getMessage ()); }
try {
createPipeline ("validate ( foo )"); // illegal param
System.err.println ("** didn't report error");
} catch (Exception e) {
System.err.println ("== err: " + e.getMessage ()); }
try {
createPipeline ("tee"); // missing param
System.err.println ("** didn't report error");
} catch (Exception e) {
System.err.println ("== err: " + e.getMessage ()); }
try {
// only builtins so far
createPipeline ("com.example.xml.FilterClass");
System.err.println ("** didn't report error");
} catch (Exception e) {
System.err.println ("== err: " + e.getMessage ()); }
} catch (Exception e) {
e.printStackTrace ();
}
}
/**/
}
+413
View File
@@ -0,0 +1,413 @@
/* TeeConsumer.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., 59 Temple Place, Suite 330, Boston, MA
02111-1307 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.pipeline;
import java.io.IOException;
import org.xml.sax.*;
import org.xml.sax.ext.*;
//import gnu.xml.util;
/**
* Fans its events out to two other consumers, a "tee" filter stage in an
* event pipeline. Networks can be assembled with multiple output points.
*
* <p> Error handling should be simple if you remember that exceptions
* you throw will cancel later stages in that callback's pipeline, and
* generally the producer will stop if it sees such an exception. You
* may want to protect your pipeline against such backflows, making a
* kind of reverse filter (or valve?) so that certain exceptions thrown by
* your pipeline will caught and handled before the producer sees them.
* Just use a "try/catch" block, rememebering that really important
* cleanup tasks should be in "finally" clauses.
*
* <p> That issue isn't unique to "tee" consumers, but tee consumers have
* the additional twist that exceptions thrown by the first consumer
* will cause the second consumer not to see the callback (except for
* the endDocument callback, which signals state cleanup).
*
* @author David Brownell
*/
final public class TeeConsumer
implements EventConsumer,
ContentHandler, DTDHandler,
LexicalHandler,DeclHandler
{
private EventConsumer first, rest;
// cached to minimize time overhead
private ContentHandler docFirst, docRest;
private DeclHandler declFirst, declRest;
private LexicalHandler lexFirst, lexRest;
/**
* Constructs a consumer which sends all its events to the first
* consumer, and then the second one. If the first consumer throws
* an exception, the second one will not see the event which
* caused that exception to be reported.
*
* @param car The first consumer to get the events
* @param cdr The second consumer to get the events
*/
public TeeConsumer (EventConsumer car, EventConsumer cdr)
{
if (car == null || cdr == null)
throw new NullPointerException ();
first = car;
rest = cdr;
//
// Cache the handlers.
//
docFirst = first.getContentHandler ();
docRest = rest.getContentHandler ();
// DTD handler isn't cached (rarely needed)
try {
declFirst = null;
declFirst = (DeclHandler) first.getProperty (
EventFilter.DECL_HANDLER);
} catch (SAXException e) {}
try {
declRest = null;
declRest = (DeclHandler) rest.getProperty (
EventFilter.DECL_HANDLER);
} catch (SAXException e) {}
try {
lexFirst = null;
lexFirst = (LexicalHandler) first.getProperty (
EventFilter.LEXICAL_HANDLER);
} catch (SAXException e) {}
try {
lexRest = null;
lexRest = (LexicalHandler) rest.getProperty (
EventFilter.LEXICAL_HANDLER);
} catch (SAXException e) {}
}
/* FIXME
/**
* Constructs a pipeline, and is otherwise a shorthand for the
* two-consumer constructor for this class.
*
* @param first Description of the first pipeline to get events,
* which will be passed to {@link PipelineFactory#createPipeline}
* @param rest The second pipeline to get the events
* /
// constructor used by PipelineFactory
public TeeConsumer (String first, EventConsumer rest)
throws IOException
{
this (PipelineFactory.createPipeline (first), rest);
}
*/
/** Returns the first pipeline to get event calls. */
public EventConsumer getFirst ()
{ return first; }
/** Returns the second pipeline to get event calls. */
public EventConsumer getRest ()
{ return rest; }
/** Returns the content handler being used. */
final public ContentHandler getContentHandler ()
{
if (docRest == null)
return docFirst;
if (docFirst == null)
return docRest;
return this;
}
/** Returns the dtd handler being used. */
final public DTDHandler getDTDHandler ()
{
// not cached (hardly used)
if (rest.getDTDHandler () == null)
return first.getDTDHandler ();
if (first.getDTDHandler () == null)
return rest.getDTDHandler ();
return this;
}
/** Returns the declaration or lexical handler being used. */
final public Object getProperty (String id)
throws SAXNotRecognizedException
{
//
// in degenerate cases, we have no work to do.
//
Object firstProp = null, restProp = null;
try { firstProp = first.getProperty (id); }
catch (SAXNotRecognizedException e) { /* ignore */ }
try { restProp = rest.getProperty (id); }
catch (SAXNotRecognizedException e) { /* ignore */ }
if (restProp == null)
return firstProp;
if (firstProp == null)
return restProp;
//
// we've got work to do; handle two builtin cases.
//
if (EventFilter.DECL_HANDLER.equals (id))
return this;
if (EventFilter.LEXICAL_HANDLER.equals (id))
return this;
//
// non-degenerate, handled by both consumers, but we don't know
// how to handle this.
//
throw new SAXNotRecognizedException ("can't tee: " + id);
}
/**
* Provides the error handler to both subsequent nodes of
* this filter stage.
*/
public void setErrorHandler (ErrorHandler handler)
{
first.setErrorHandler (handler);
rest.setErrorHandler (handler);
}
//
// ContentHandler
//
public void setDocumentLocator (Locator locator)
{
// this call is not made by all parsers
docFirst.setDocumentLocator (locator);
docRest.setDocumentLocator (locator);
}
public void startDocument ()
throws SAXException
{
docFirst.startDocument ();
docRest.startDocument ();
}
public void endDocument ()
throws SAXException
{
try {
docFirst.endDocument ();
} finally {
docRest.endDocument ();
}
}
public void startPrefixMapping (String prefix, String uri)
throws SAXException
{
docFirst.startPrefixMapping (prefix, uri);
docRest.startPrefixMapping (prefix, uri);
}
public void endPrefixMapping (String prefix)
throws SAXException
{
docFirst.endPrefixMapping (prefix);
docRest.endPrefixMapping (prefix);
}
public void skippedEntity (String name)
throws SAXException
{
docFirst.skippedEntity (name);
docRest.skippedEntity (name);
}
public void startElement (String uri, String localName,
String qName, Attributes atts)
throws SAXException
{
docFirst.startElement (uri, localName, qName, atts);
docRest.startElement (uri, localName, qName, atts);
}
public void endElement (String uri, String localName, String qName)
throws SAXException
{
docFirst.endElement (uri, localName, qName);
docRest.endElement (uri, localName, qName);
}
public void processingInstruction (String target, String data)
throws SAXException
{
docFirst.processingInstruction (target, data);
docRest.processingInstruction (target, data);
}
public void characters (char ch [], int start, int length)
throws SAXException
{
docFirst.characters (ch, start, length);
docRest.characters (ch, start, length);
}
public void ignorableWhitespace (char ch [], int start, int length)
throws SAXException
{
docFirst.ignorableWhitespace (ch, start, length);
docRest.ignorableWhitespace (ch, start, length);
}
//
// DTDHandler
//
public void notationDecl (String name, String publicId, String systemId)
throws SAXException
{
DTDHandler l1 = first.getDTDHandler ();
DTDHandler l2 = rest.getDTDHandler ();
l1.notationDecl (name, publicId, systemId);
l2.notationDecl (name, publicId, systemId);
}
public void unparsedEntityDecl (String name,
String publicId, String systemId,
String notationName
) throws SAXException
{
DTDHandler l1 = first.getDTDHandler ();
DTDHandler l2 = rest.getDTDHandler ();
l1.unparsedEntityDecl (name, publicId, systemId, notationName);
l2.unparsedEntityDecl (name, publicId, systemId, notationName);
}
//
// DeclHandler
//
public void attributeDecl (String eName, String aName,
String type,
String mode, String value)
throws SAXException
{
declFirst.attributeDecl (eName, aName, type, mode, value);
declRest.attributeDecl (eName, aName, type, mode, value);
}
public void elementDecl (String name, String model)
throws SAXException
{
declFirst.elementDecl (name, model);
declRest.elementDecl (name, model);
}
public void externalEntityDecl (String name,
String publicId, String systemId)
throws SAXException
{
declFirst.externalEntityDecl (name, publicId, systemId);
declRest.externalEntityDecl (name, publicId, systemId);
}
public void internalEntityDecl (String name, String value)
throws SAXException
{
declFirst.internalEntityDecl (name, value);
declRest.internalEntityDecl (name, value);
}
//
// LexicalHandler
//
public void comment (char ch [], int start, int length)
throws SAXException
{
lexFirst.comment (ch, start, length);
lexRest.comment (ch, start, length);
}
public void startCDATA ()
throws SAXException
{
lexFirst.startCDATA ();
lexRest.startCDATA ();
}
public void endCDATA ()
throws SAXException
{
lexFirst.endCDATA ();
lexRest.endCDATA ();
}
public void startEntity (String name)
throws SAXException
{
lexFirst.startEntity (name);
lexRest.startEntity (name);
}
public void endEntity (String name)
throws SAXException
{
lexFirst.endEntity (name);
lexRest.endEntity (name);
}
public void startDTD (String name, String publicId, String systemId)
throws SAXException
{
lexFirst.startDTD (name, publicId, systemId);
lexRest.startDTD (name, publicId, systemId);
}
public void endDTD ()
throws SAXException
{
lexFirst.endDTD ();
lexRest.endDTD ();
}
}
+117
View File
@@ -0,0 +1,117 @@
/* TextConsumer.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., 59 Temple Place, Suite 330, Boston, MA
02111-1307 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.pipeline;
import java.io.*;
import org.xml.sax.*;
import gnu.xml.util.XMLWriter;
/**
* Terminates a pipeline, consuming events to print them as well formed
* XML (or XHTML) text.
*
* <p> Input must be well formed, and must include XML names (e.g. the
* prefixes and prefix declarations must be present), or the output of
* this class is undefined.
*
* @see NSFilter
* @see WellFormednessFilter
*
* @author David Brownell
*/
public class TextConsumer extends XMLWriter implements EventConsumer
{
/**
* Constructs an event consumer which echoes its input as text,
* optionally adhering to some basic XHTML formatting options
* which increase interoperability with old (v3) browsers.
*
* <p> For the best interoperability, when writing as XHTML only
* ASCII characters are emitted; other characters are turned to
* entity or character references as needed, and no XML declaration
* is provided in the document.
*/
public TextConsumer (Writer w, boolean isXhtml)
throws IOException
{
super (w, isXhtml ? "US-ASCII" : null);
setXhtml (isXhtml);
}
/**
* Constructs a consumer that writes its input as XML text.
* XHTML rules are not followed.
*/
public TextConsumer (Writer w)
throws IOException
{
this (w, false);
}
/**
* Constructs a consumer that writes its input as XML text,
* encoded in UTF-8. XHTML rules are not followed.
*/
public TextConsumer (OutputStream out)
throws IOException
{
this (new OutputStreamWriter (out, "UTF8"), false);
}
/** <b>EventConsumer</b> Returns the document handler being used. */
public ContentHandler getContentHandler ()
{ return this; }
/** <b>EventConsumer</b> Returns the dtd handler being used. */
public DTDHandler getDTDHandler ()
{ return this; }
/** <b>XMLReader</b>Retrieves a property (lexical and decl handlers) */
public Object getProperty (String propertyId)
throws SAXNotRecognizedException
{
if (EventFilter.LEXICAL_HANDLER.equals (propertyId))
return this;
if (EventFilter.DECL_HANDLER.equals (propertyId))
return this;
throw new SAXNotRecognizedException (propertyId);
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,362 @@
/* WellFormednessFilter.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., 59 Temple Place, Suite 330, Boston, MA
02111-1307 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.pipeline;
import java.util.EmptyStackException;
import java.util.Stack;
import gnu.xml.aelfred2.SAXDriver;
import org.xml.sax.*;
import org.xml.sax.ext.*;
/**
* This filter reports fatal exceptions in the case of event streams that
* are not well formed. The rules currently tested include: <ul>
*
* <li>setDocumentLocator ... may be called only before startDocument
*
* <li>startDocument/endDocument ... must be paired, and all other
* calls (except setDocumentLocator) must be nested within these.
*
* <li>startElement/endElement ... must be correctly paired, and
* may never appear within CDATA sections.
*
* <li>comment ... can't contain "--"
*
* <li>character data ... can't contain "]]&gt;"
*
* <li>whitespace ... can't contain CR
*
* <li>whitespace and character data must be within an element
*
* <li>processing instruction ... can't contain "?&gt;" or CR
*
* <li>startCDATA/endCDATA ... must be correctly paired.
*
* </ul>
*
* <p> Other checks for event stream correctness may be provided in
* the future. For example, insisting that
* entity boundaries nest correctly,
* namespace scopes nest correctly,
* namespace values never contain relative URIs,
* attributes don't have "&lt;" characters;
* and more.
*
* @author David Brownell
*/
public final class WellFormednessFilter extends EventFilter
{
private boolean startedDoc;
private Stack elementStack = new Stack ();
private boolean startedCDATA;
private String dtdState = "before";
/**
* Swallows all events after performing well formedness checks.
*/
// constructor used by PipelineFactory
public WellFormednessFilter ()
{ this (null); }
/**
* Passes events through to the specified consumer, after first
* processing them.
*/
// constructor used by PipelineFactory
public WellFormednessFilter (EventConsumer consumer)
{
super (consumer);
setContentHandler (this);
setDTDHandler (this);
try {
setProperty (LEXICAL_HANDLER, this);
} catch (SAXException e) { /* can't happen */ }
}
/**
* Resets state as if any preceding event stream was well formed.
* Particularly useful if it ended through some sort of error,
* and the endDocument call wasn't made.
*/
public void reset ()
{
startedDoc = false;
startedCDATA = false;
elementStack.removeAllElements ();
}
private SAXParseException getException (String message)
{
SAXParseException e;
Locator locator = getDocumentLocator ();
if (locator == null)
return new SAXParseException (message, null, null, -1, -1);
else
return new SAXParseException (message, locator);
}
private void fatalError (String message)
throws SAXException
{
SAXParseException e = getException (message);
ErrorHandler handler = getErrorHandler ();
if (handler != null)
handler.fatalError (e);
throw e;
}
/**
* Throws an exception when called after startDocument.
*
* @param locator the locator, to be used in error reporting or relative
* URI resolution.
*
* @exception IllegalStateException when called after the document
* has already been started
*/
public void setDocumentLocator (Locator locator)
{
if (startedDoc)
throw new IllegalStateException (
"setDocumentLocator called after startDocument");
super.setDocumentLocator (locator);
}
public void startDocument () throws SAXException
{
if (startedDoc)
fatalError ("startDocument called more than once");
startedDoc = true;
startedCDATA = false;
elementStack.removeAllElements ();
super.startDocument ();
}
public void startElement (
String uri, String localName,
String qName, Attributes atts
) throws SAXException
{
if (!startedDoc)
fatalError ("callback outside of document?");
if ("inside".equals (dtdState))
fatalError ("element inside DTD?");
else
dtdState = "after";
if (startedCDATA)
fatalError ("element inside CDATA section");
if (qName == null || "".equals (qName))
fatalError ("startElement name missing");
elementStack.push (qName);
super.startElement (uri, localName, qName, atts);
}
public void endElement (String uri, String localName, String qName)
throws SAXException
{
if (!startedDoc)
fatalError ("callback outside of document?");
if (startedCDATA)
fatalError ("element inside CDATA section");
if (qName == null || "".equals (qName))
fatalError ("endElement name missing");
try {
String top = (String) elementStack.pop ();
if (!qName.equals (top))
fatalError ("<" + top + " ...>...</" + qName + ">");
// XXX could record/test namespace info
} catch (EmptyStackException e) {
fatalError ("endElement without startElement: </" + qName + ">");
}
super.endElement (uri, localName, qName);
}
public void endDocument () throws SAXException
{
if (!startedDoc)
fatalError ("callback outside of document?");
dtdState = "before";
startedDoc = false;
super.endDocument ();
}
public void startDTD (String root, String publicId, String systemId)
throws SAXException
{
if (!startedDoc)
fatalError ("callback outside of document?");
if ("before" != dtdState)
fatalError ("two DTDs?");
if (!elementStack.empty ())
fatalError ("DTD must precede root element");
dtdState = "inside";
super.startDTD (root, publicId, systemId);
}
public void notationDecl (String name, String publicId, String systemId)
throws SAXException
{
// FIXME: not all parsers will report startDTD() ...
// we'd rather insist we're "inside".
if ("after" == dtdState)
fatalError ("not inside DTD");
super.notationDecl (name, publicId, systemId);
}
public void unparsedEntityDecl (String name,
String publicId, String systemId, String notationName)
throws SAXException
{
// FIXME: not all parsers will report startDTD() ...
// we'd rather insist we're "inside".
if ("after" == dtdState)
fatalError ("not inside DTD");
super.unparsedEntityDecl (name, publicId, systemId, notationName);
}
// FIXME: add the four DeclHandler calls too
public void endDTD ()
throws SAXException
{
if (!startedDoc)
fatalError ("callback outside of document?");
if ("inside" != dtdState)
fatalError ("DTD ends without start?");
dtdState = "after";
super.endDTD ();
}
public void characters (char ch [], int start, int length)
throws SAXException
{
int here = start, end = start + length;
if (elementStack.empty ())
fatalError ("characters must be in an element");
while (here < end) {
if (ch [here++] != ']')
continue;
if (here == end) // potential problem ...
continue;
if (ch [here++] != ']')
continue;
if (here == end) // potential problem ...
continue;
if (ch [here++] == '>')
fatalError ("character data can't contain \"]]>\"");
}
super.characters (ch, start, length);
}
public void ignorableWhitespace (char ch [], int start, int length)
throws SAXException
{
int here = start, end = start + length;
if (elementStack.empty ())
fatalError ("characters must be in an element");
while (here < end) {
if (ch [here++] == '\r')
fatalError ("whitespace can't contain CR");
}
super.ignorableWhitespace (ch, start, length);
}
public void processingInstruction (String target, String data)
throws SAXException
{
if (data.indexOf ('\r') > 0)
fatalError ("PIs can't contain CR");
if (data.indexOf ("?>") > 0)
fatalError ("PIs can't contain \"?>\"");
}
public void comment (char ch [], int start, int length)
throws SAXException
{
if (!startedDoc)
fatalError ("callback outside of document?");
if (startedCDATA)
fatalError ("comments can't nest in CDATA");
int here = start, end = start + length;
while (here < end) {
if (ch [here] == '\r')
fatalError ("comments can't contain CR");
if (ch [here++] != '-')
continue;
if (here == end)
fatalError ("comments can't end with \"--->\"");
if (ch [here++] == '-')
fatalError ("comments can't contain \"--\"");
}
super.comment (ch, start, length);
}
public void startCDATA ()
throws SAXException
{
if (!startedDoc)
fatalError ("callback outside of document?");
if (startedCDATA)
fatalError ("CDATA starts can't nest");
startedCDATA = true;
super.startCDATA ();
}
public void endCDATA ()
throws SAXException
{
if (!startedDoc)
fatalError ("callback outside of document?");
if (!startedCDATA)
fatalError ("CDATA end without start?");
startedCDATA = false;
super.endCDATA ();
}
}
@@ -0,0 +1,580 @@
/* XIncludeFilter.java --
Copyright (C) 2001,2002 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., 59 Temple Place, Suite 330, Boston, MA
02111-1307 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.pipeline;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Stack;
import java.util.Vector;
import org.xml.sax.Attributes;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
import gnu.xml.util.Resolver;
/**
* Filter to process an XPointer-free subset of
* <a href="http://www.w3.org/TR/xinclude">XInclude</a>, supporting its
* use as a kind of replacement for parsed general entities.
* XInclude works much like the <code>#include</code> of C/C++ but
* works for XML documents as well as unparsed text files.
* Restrictions from the 17-Sept-2002 CR draft of XInclude are as follows:
*
* <ul>
*
* <li> URIs must not include fragment identifiers.
* The CR specifies support for XPointer <em>element()</em> fragment IDs,
* which is not currently implemented here.
*
* <li> <em>xi:fallback</em> handling of resource errors is not
* currently supported.
*
* <li> DTDs are not supported in included files, since the SAX DTD events
* must have completely preceded any included file.
* The CR explicitly allows the DTD related portions of the infoset to
* grow as an effect of including XML documents.
*
* <li> <em>xml:base</em> fixup isn't done.
*
* </ul>
*
* <p> XML documents that are included will normally be processed using
* the default SAX namespace rules, meaning that prefix information may
* be discarded. This may be changed with {@link #setSavingPrefixes
* setSavingPrefixes()}. <em>You are strongly advised to do this.</em>
*
* <p> Note that XInclude allows highly incompatible implementations, which
* are specialized to handle application-specific infoset extensions. Some
* such implementations can be implemented by subclassing this one, but
* they may only be substituted in applications at "user option".
*
* <p>TBD: "IURI" handling.
*
* @author David Brownell
*/
public class XIncludeFilter extends EventFilter implements Locator
{
private Hashtable extEntities = new Hashtable (5, 5);
private int ignoreCount;
private Stack uris = new Stack ();
private Locator locator;
private Vector inclusions = new Vector (5, 5);
private boolean savingPrefixes;
/**
*/
public XIncludeFilter (EventConsumer next)
throws SAXException
{
super (next);
setContentHandler (this);
// DTDHandler callbacks pass straight through
setProperty (DECL_HANDLER, this);
setProperty (LEXICAL_HANDLER, this);
}
private void fatal (SAXParseException e) throws SAXException
{
ErrorHandler eh;
eh = getErrorHandler ();
if (eh != null)
eh.fatalError (e);
throw e;
}
/**
* Passes "this" down the filter chain as a proxy locator.
*/
public void setDocumentLocator (Locator locator)
{
this.locator = locator;
super.setDocumentLocator (this);
}
/** Used for proxy locator; do not call directly. */
public String getSystemId ()
{ return (locator == null) ? null : locator.getSystemId (); }
/** Used for proxy locator; do not call directly. */
public String getPublicId ()
{ return (locator == null) ? null : locator.getPublicId (); }
/** Used for proxy locator; do not call directly. */
public int getLineNumber ()
{ return (locator == null) ? -1 : locator.getLineNumber (); }
/** Used for proxy locator; do not call directly. */
public int getColumnNumber ()
{ return (locator == null) ? -1 : locator.getColumnNumber (); }
/**
* Assigns the flag controlling the setting of the SAX2
* <em>namespace-prefixes</em> flag.
*/
public void setSavingPrefixes (boolean flag)
{ savingPrefixes = flag; }
/**
* Returns the flag controlling the setting of the SAX2
* <em>namespace-prefixes</em> flag when parsing included documents.
* The default value is the SAX2 default (false), which discards
* information that can be useful.
*/
public boolean isSavingPrefixes ()
{ return savingPrefixes; }
//
// Two mechanisms are interacting here.
//
// - XML Base implies a stack of base URIs, updated both by
// "real entity" boundaries and element boundaries.
//
// - Active "Real Entities" (for document and general entities,
// and by xincluded files) are tracked to prevent circular
// inclusions.
//
private String addMarker (String uri)
throws SAXException
{
if (locator != null && locator.getSystemId () != null)
uri = locator.getSystemId ();
// guard against InputSource objects without system IDs
if (uri == null)
fatal (new SAXParseException ("Entity URI is unknown", locator));
try {
URL url = new URL (uri);
uri = url.toString ();
if (inclusions.contains (uri))
fatal (new SAXParseException (
"XInclude, circular inclusion", locator));
inclusions.addElement (uri);
uris.push (url);
} catch (IOException e) {
// guard against illegal relative URIs (Xerces)
fatal (new SAXParseException ("parser bug: relative URI",
locator, e));
}
return uri;
}
private void pop (String uri)
{
inclusions.removeElement (uri);
uris.pop ();
}
//
// Document entity boundaries get both treatments.
//
public void startDocument () throws SAXException
{
ignoreCount = 0;
addMarker (null);
super.startDocument ();
}
public void endDocument () throws SAXException
{
inclusions.setSize (0);
extEntities.clear ();
uris.setSize (0);
super.endDocument ();
}
//
// External general entity boundaries get both treatments.
//
public void externalEntityDecl (String name,
String publicId, String systemId)
throws SAXException
{
if (name.charAt (0) == '%')
return;
try {
URL url = new URL (locator.getSystemId ());
systemId = new URL (url, systemId).toString ();
} catch (IOException e) {
// what could we do?
}
extEntities.put (name, systemId);
}
public void startEntity (String name)
throws SAXException
{
if (ignoreCount != 0) {
ignoreCount++;
return;
}
String uri = (String) extEntities.get (name);
if (uri != null)
addMarker (uri);
super.startEntity (name);
}
public void endEntity (String name)
throws SAXException
{
if (ignoreCount != 0) {
if (--ignoreCount != 0)
return;
}
String uri = (String) extEntities.get (name);
if (uri != null)
pop (uri);
super.endEntity (name);
}
//
// element boundaries only affect the base URI stack,
// unless they're XInclude elements.
//
public void
startElement (String uri, String localName, String qName, Attributes atts)
throws SAXException
{
if (ignoreCount != 0) {
ignoreCount++;
return;
}
URL baseURI = (URL) uris.peek ();
String base;
base = atts.getValue ("http://www.w3.org/XML/1998/namespace", "base");
if (base == null)
uris.push (baseURI);
else {
URL url;
if (base.indexOf ('#') != -1)
fatal (new SAXParseException (
"xml:base with fragment: " + base,
locator));
try {
baseURI = new URL (baseURI, base);
uris.push (baseURI);
} catch (Exception e) {
fatal (new SAXParseException (
"xml:base with illegal uri: " + base,
locator, e));
}
}
if (!"http://www.w3.org/2001/XInclude".equals (uri)) {
super.startElement (uri, localName, qName, atts);
return;
}
if ("include".equals (localName)) {
String href = atts.getValue ("href");
String parse = atts.getValue ("parse");
String encoding = atts.getValue ("encoding");
URL url = (URL) uris.peek ();
SAXParseException x = null;
if (href == null)
fatal (new SAXParseException (
"XInclude missing href",
locator));
if (href.indexOf ('#') != -1)
fatal (new SAXParseException (
"XInclude with fragment: " + href,
locator));
if (parse == null || "xml".equals (parse))
x = xinclude (url, href);
else if ("text".equals (parse))
x = readText (url, href, encoding);
else
fatal (new SAXParseException (
"unknown XInclude parsing mode: " + parse,
locator));
if (x == null) {
// strip out all child content
ignoreCount++;
return;
}
// FIXME the 17-Sept-2002 CR of XInclude says we "must"
// use xi:fallback elements to handle resource errors,
// if they exist.
fatal (x);
} else if ("fallback".equals (localName)) {
fatal (new SAXParseException (
"illegal top level XInclude 'fallback' element",
locator));
} else {
ErrorHandler eh = getErrorHandler ();
// CR doesn't say this is an error
if (eh != null)
eh.warning (new SAXParseException (
"unrecognized toplevel XInclude element: " + localName,
locator));
super.startElement (uri, localName, qName, atts);
}
}
public void endElement (String uri, String localName, String qName)
throws SAXException
{
if (ignoreCount != 0) {
if (--ignoreCount != 0)
return;
}
uris.pop ();
if (!("http://www.w3.org/2001/XInclude".equals (uri)
&& "include".equals (localName)))
super.endElement (uri, localName, qName);
}
//
// ignore all content within non-empty xi:include elements
//
public void characters (char ch [], int start, int length)
throws SAXException
{
if (ignoreCount == 0)
super.characters (ch, start, length);
}
public void processingInstruction (String target, String value)
throws SAXException
{
if (ignoreCount == 0)
super.processingInstruction (target, value);
}
public void ignorableWhitespace (char ch [], int start, int length)
throws SAXException
{
if (ignoreCount == 0)
super.ignorableWhitespace (ch, start, length);
}
public void comment (char ch [], int start, int length)
throws SAXException
{
if (ignoreCount == 0)
super.comment (ch, start, length);
}
public void startCDATA () throws SAXException
{
if (ignoreCount == 0)
super.startCDATA ();
}
public void endCDATA () throws SAXException
{
if (ignoreCount == 0)
super.endCDATA ();
}
public void startPrefixMapping (String prefix, String uri)
throws SAXException
{
if (ignoreCount == 0)
super.startPrefixMapping (prefix, uri);
}
public void endPrefixMapping (String prefix) throws SAXException
{
if (ignoreCount == 0)
super.endPrefixMapping (prefix);
}
public void skippedEntity (String name) throws SAXException
{
if (ignoreCount == 0)
super.skippedEntity (name);
}
// JDK 1.1 seems to need it to be done this way, sigh
void setLocator (Locator l) { locator = l; }
Locator getLocator () { return locator; }
//
// for XIncluded entities, manage the current locator and
// filter out events that would be incorrect to report
//
private class Scrubber extends EventFilter
{
Scrubber (EventFilter f)
throws SAXException
{
// delegation passes to next in chain
super (f);
// process all content events
super.setContentHandler (this);
super.setProperty (LEXICAL_HANDLER, this);
// drop all DTD events
super.setDTDHandler (null);
super.setProperty (DECL_HANDLER, null);
}
// maintain proxy locator
// only one startDocument()/endDocument() pair per event stream
public void setDocumentLocator (Locator l)
{ setLocator (l); }
public void startDocument ()
{ }
public void endDocument ()
{ }
private void reject (String message) throws SAXException
{ fatal (new SAXParseException (message, getLocator ())); }
// only the DTD from the "base document" gets reported
public void startDTD (String root, String publicId, String systemId)
throws SAXException
{ reject ("XIncluded DTD: " + systemId); }
public void endDTD ()
throws SAXException
{ reject ("XIncluded DTD"); }
// ... so this should never happen
public void skippedEntity (String name) throws SAXException
{ reject ("XInclude skipped entity: " + name); }
// since we rejected DTDs, only builtin entities can be reported
}
// <xi:include parse='xml' ...>
// relative to the base URI passed
private SAXParseException xinclude (URL url, String href)
throws SAXException
{
XMLReader helper;
Scrubber scrubber;
Locator savedLocator = locator;
// start with a parser acting just like our input
// modulo DTD-ish stuff (validation flag, entity resolver)
helper = XMLReaderFactory.createXMLReader ();
helper.setErrorHandler (getErrorHandler ());
helper.setFeature (FEATURE_URI + "namespace-prefixes", true);
// Set up the proxy locator and event filter.
scrubber = new Scrubber (this);
locator = null;
bind (helper, scrubber);
// Merge the included document, except its DTD
try {
url = new URL (url, href);
href = url.toString ();
if (inclusions.contains (href))
fatal (new SAXParseException (
"XInclude, circular inclusion", locator));
inclusions.addElement (href);
uris.push (url);
helper.parse (new InputSource (href));
return null;
} catch (java.io.IOException e) {
return new SAXParseException (href, locator, e);
} finally {
pop (href);
locator = savedLocator;
}
}
// <xi:include parse='text' ...>
// relative to the base URI passed
private SAXParseException readText (URL url, String href, String encoding)
throws SAXException
{
InputStream in = null;
try {
URLConnection conn;
InputStreamReader reader;
char buf [] = new char [4096];
int count;
url = new URL (url, href);
conn = url.openConnection ();
in = conn.getInputStream ();
if (encoding == null)
encoding = Resolver.getEncoding (conn.getContentType ());
if (encoding == null) {
ErrorHandler eh = getErrorHandler ();
if (eh != null)
eh.warning (new SAXParseException (
"guessing text encoding for URL: " + url,
locator));
reader = new InputStreamReader (in);
} else
reader = new InputStreamReader (in, encoding);
while ((count = reader.read (buf, 0, buf.length)) != -1)
super.characters (buf, 0, count);
in.close ();
return null;
} catch (IOException e) {
return new SAXParseException (
"can't XInclude text",
locator, e);
}
}
}
+131
View File
@@ -0,0 +1,131 @@
/* XsltFilter.java --
Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA
02111-1307 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.pipeline;
import java.io.IOException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.*;
import javax.xml.transform.stream.StreamSource;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
/**
* Packages an XSLT transform as a pipeline component.
* Note that all DTD events (callbacks to DeclHandler and DTDHandler
* interfaces) are discarded, although XSLT transforms may be set up to
* use the LexicalHandler to write DTDs with only an external subset.
* Not every XSLT engine will necessarily be usable with this filter,
* but current versions of
* <a href="http://saxon.sourceforge.net">SAXON</a> and
* <a href="http://xml.apache.org/xalan-j">Xalan</a> should work well.
*
* @see TransformerFactory
*
* @author David Brownell
*/
final public class XsltFilter extends EventFilter
{
/**
* Creates a filter that performs the specified transform.
* Uses the JAXP 1.1 interfaces to access the default XSLT
* engine configured for in the current execution context,
* and parses the stylesheet without custom EntityResolver
* or ErrorHandler support.
*
* @param stylesheet URI for the stylesheet specifying the
* XSLT transform
* @param next provides the ContentHandler and LexicalHandler
* to receive XSLT output.
* @exception SAXException if the stylesheet can't be parsed
* @exception IOException if there are difficulties
* bootstrapping the XSLT engine, such as it not supporting
* SAX well enough to use this way.
*/
public XsltFilter (String stylesheet, EventConsumer next)
throws SAXException, IOException
{
// First, get a transformer with the stylesheet preloaded
TransformerFactory tf = null;
TransformerHandler th;
try {
SAXTransformerFactory stf;
tf = TransformerFactory.newInstance ();
if (!tf.getFeature (SAXTransformerFactory.FEATURE) // sax inputs
|| !tf.getFeature (SAXResult.FEATURE) // sax outputs
|| !tf.getFeature (StreamSource.FEATURE) // stylesheet
)
throw new IOException ("XSLT factory ("
+ tf.getClass ().getName ()
+ ") does not support SAX");
stf = (SAXTransformerFactory) tf;
th = stf.newTransformerHandler (new StreamSource (stylesheet));
} catch (TransformerConfigurationException e) {
throw new IOException ("XSLT factory ("
+ (tf == null
? "none available"
: tf.getClass ().getName ())
+ ") configuration error, "
+ e.getMessage ()
);
}
// Hook its outputs up to the pipeline ...
SAXResult out = new SAXResult ();
out.setHandler (next.getContentHandler ());
try {
LexicalHandler lh;
lh = (LexicalHandler) next.getProperty (LEXICAL_HANDLER);
out.setLexicalHandler (lh);
} catch (Exception e) {
// ignore
}
th.setResult (out);
// ... and make sure its inputs look like ours.
setContentHandler (th);
setProperty (LEXICAL_HANDLER, th);
}
}
+255
View File
@@ -0,0 +1,255 @@
<html><head><title>
blah
<!--
/*
* Copyright (C) 1999-2001 The Free Software Foundation, Inc.
*/
-->
</title></head><body>
<p>This package exposes a kind of XML processing pipeline, based on sending
SAX events, which can be used as components of application architectures.
Pipelines are used to convey streams of processing events from a producer
to one or more consumers, and to let each consumer control the data seen by
later consumers.
<p> There is a <a href="PipelineFactory.html">PipelineFactory</a> class which
accepts a syntax describing how to construct some simple pipelines. Strings
describing such pipelines can be used in command line tools (see the
<a href="../util/DoParse.html">DoParse</a> class)
and in other places that it is
useful to let processing be easily reconfigured. Pipelines can of course
be constructed programmatically, providing access to options that the
factory won't.
<p> Web applications are supported by making it easy for servlets (or
non-Java web application components) to be part of a pipeline. They can
originate XML (or XHTML) data through an <em>InputSource</em> or in
response to XML messages sent from clients using <em>CallFilter</em>
pipeline stages. Such facilities are available using the simple syntax
for pipeline construction.
<h2> Programming Models </h2>
<p> Pipelines should be simple to understand.
<ul>
<li> XML content, typically entire documents,
is pushed through consumers by producers.
<li> Pipelines are basically about consuming SAX2 callback events,
where the events encapsulate XML infoset-level data.<ul>
<li> Pipelines are constructed by taking one or more consumer
stages and combining them to produce a composite consumer.
<li> A pipeline is presumed to have pending tasks and state from
the beginning of its ContentHandler.startDocument() callback until
it's returned from its ContentHandler.doneDocument() callback.
<li> Pipelines may have multiple output stages ("fan-out")
or multiple input stages ("fan-in") when appropriate.
<li> Pipelines may be long-lived, but need not be.
</ul>
<li> There is flexibility about event production. <ul>
<li> SAX2 XMLReader objects are producers, which
provide a high level "pull" model: documents (text or DOM) are parsed,
and the parser pushes individual events through the pipeline.
<li> Events can be pushed directly to event consumer components
by application modules, if they invoke SAX2 callbacks directly.
That is, application modules use the XML Infoset as exposed
through SAX2 event callbacks.
</ul>
<li> Multiple producer threads may concurrently access a pipeline,
if they coordinate appropriately.
<li> Pipeline processing is not the only framework applications
will use.
</ul>
<h3> Producers: XMLReader or Custom </h3>
<p> Many producers will be SAX2 XMLReader objects, and
will read (pull) data which is then written (pushed) as events.
Typically these will parse XML text (acquired from
<code>org.xml.sax.helpers.XMLReaderFactory</code>) or a DOM tree
(using a <code><a href="../util/DomParser.html">DomParser</a></code>)
These may be bound to event consumer using a convenience routine,
<em><a href="EventFilter.html">EventFilter</a>.bind()</em>.
Once bound, these producers may be given additional documents to
sent through its pipeline.
<p> In other cases, you will write producers yourself. For example, some
data structures might know how to write themselves out using one or
more XML models, expressed as sequences of SAX2 event callbacks.
An application module might
itself be a producer, issuing startDocument and endDocument events
and then asking those data structures to write themselves out to a
given EventConsumer, or walking data structures (such as JDBC query
results) and applying its own conversion rules. WAP format XML
(WBMXL) can be directly converted to producer output.
<p> SAX2 introduced an "XMLFilter" interface, which is a kind of XMLReader.
It is most useful in conjunction with its XMLFilterImpl helper class;
see the <em><a href="EventFilter.html">EventFilter</a></em> javadoc
for information contrasting that XMLFilterImpl approach with the
relevant parts of this pipeline framework. Briefly, such XMLFilterImpl
children can be either producers or consumers, and are more limited in
configuration flexibility. In this framework, the focus of filters is
on the EventConsumer side; see the section on
<a href="#fitting">pipe fitting</a> below.
<h3> Consume to Standard or Custom Data Representations </h3>
<p> Many consumers will be used to create standard representations of XML
data. The <a href="TextConsumer.html">TextConsumer</a> takes its events
and writes them as text for a single XML document,
using an internal <a href="../util/XMLWriter.html">XMLWriter</a>.
The <a href="DomConsumer.html">DomConsumer</a> takes its events and uses
them to create and populate a DOM Document.
<p> In other cases, you will write consumers yourself. For example,
you might use a particular unmarshaling filter to produce objects
that fit your application's requirements, instead of using DOM.
Such consumers work at the level of XML data models, rather than with
specific representations such as XML text or a DOM tree. You could
convert your output directly to WAP format data (WBXML).
<h3><a name="fitting">Pipe Fitting</a></h3>
<p> Pipelines are composite event consumers, with each stage having
the opportunity to transform the data before delivering it to any
subsequent stages.
<p> The <a href="PipelineFactory.html">PipelineFactory</a> class
provides access to much of this functionality through a simple syntax.
See the table in that class's javadoc describing a number of standard
components. Direct API calls are still needed for many of the most
interesting pipeline configurations, including ones leveraging actual
or logical concurrency.
<p> Four basic types of pipe fitting are directly supported. These may
be used to construct complex pipeline networks. <ul>
<li> <a href="TeeConsumer.html">TeeConsumer</a> objects split event
flow so it goes to two two different consumers, one before the other.
This is a basic form of event fan-out; you can use this class to
copy events to any number of output pipelines.
<li> Clients can call remote components through HTTP or HTTPS using
the <a href="CallFilter.html">CallFilter</a> component, and Servlets
can implement such components by extending the
<a href="XmlServlet.html">XmlServlet</a> component. Java is not
required on either end, and transport protocols other than HTTP may
also be used.
<li> <a href="EventFilter.html">EventFilter</a> objects selectively
provide handling for callbacks, and can pass unhandled ones to a
subsequent stage. They are often subclassed, since much of the
basic filtering machinery is already in place in the base class.
<li> Applications can merge two event flows by just using the same
consumer in each one. If multiple threads are in use, synchronization
needs to be addressed by the appropriate application level policy.
</ul>
<p> Note that filters can be as complex as
<a href="XsltFilter.html">XSLT transforms</a>
available) on input data, or as simple as removing simple syntax data
such as ignorable whitespace, comments, and CDATA delimiters.
Some simple "built-in" filters are part of this package.
<h3> Coding Conventions: Filter and Terminus Stages</h3>
<p> If you follow these coding conventions, your classes may be used
directly (give the full class name) in pipeline descriptions as understood
by the PipelineFactory. There are four constructors the factory may
try to use; in order of decreasing numbers of parameters, these are: <ul>
<li> Filters that need a single String setup parameter should have
a public constructor with two parameters: that string, then the
EventConsumer holding the "next" consumer to get events.
<li> Filters that don't need setup parameters should have a public
constructor that accepts a single EventConsumer holding the "next"
consumer to get events when they are done.
<li> Terminus stages may have a public constructor taking a single
paramter: the string value of that parameter.
<li> Terminus stages may have a public no-parameters constructor.
</ul>
<p> Of course, classes may support more than one such usage convention;
if they do, they can automatically be used in multiple modes. If you
try to use a terminus class as a filter, and that terminus has a constructor
with the appropriate number of arguments, it is automatically wrapped in
a "tee" filter.
<h2> Debugging Tip: "Tee" Joints can Snapshot Data</h2>
<p> It can sometimes be hard to see what's happening, when something
goes wrong. Easily fixed: just snapshot the data. Then you can find
out where things start to go wrong.
<p> If you're using pipeline descriptors so that they're easily
administered, just stick a <em>write&nbsp;(&nbsp;filename&nbsp;)</em>
filter into the pipeline at an appropriate point.
<p> Inside your programs, you can do the same thing directly: perhaps
by saving a Writer (perhaps a StringWriter) in a variable, using that
to create a TextConsumer, and making that the first part of a tee --
splicing that into your pipeline at a convenient location.
<p> You can also use a DomConsumer to buffer the data, but remember
that DOM doesn't save all the information that XML provides, so that DOM
snapshots are relatively low fidelity. They also are substantially more
expensive in terms of memory than a StringWriter holding similar data.
<h2> Debugging Tip: Non-XML Producers</h2>
<p> Producers in pipelines don't need to start from XML
data structures, such as text in XML syntax (likely coming
from some <em>XMLReader</em> that parses XML) or a
DOM representation (perhaps with a
<a href="../util/DomParser.html">DomParser</a>).
<p> One common type of event producer will instead make
direct calls to SAX event handlers returned from an
<a href="EventConsumer.html">EventConsumer</a>.
For example, making <em>ContentHandler.startElement</em>
calls and matching <em>ContentHandler.endElement</em> calls.
<p> Applications making such calls can catch certain
common "syntax errors" by using a
<a href="WellFormednessFilter.html">WellFormednessFilter</a>.
That filter will detect (and report) erroneous input data
such as mismatched document, element, or CDATA start/end calls.
Use such a filter near the head of the pipeline that your
producer feeds, at least while debugging, to help ensure that
you're providing legal XML Infoset data.
<p> You can also arrange to validate data on the fly.
For DTD validation, you can configure a
<a href="ValidationConsumer.html">ValidationConsumer</a>
to work as a filter, using any DTD you choose.
Other validation schemes can be handled with other
validation filters.
</body></html>