| // XMLFilterImpl.java - base SAX2 filter implementation. |
| // http://www.saxproject.org |
| // Written by David Megginson |
| // NO WARRANTY! This class is in the Public Domain. |
| // $Id: XMLFilterImpl.java,v 1.9 2004/04/26 17:34:35 dmegginson Exp $ |
| |
| using System; |
| using System.IO; |
| |
| namespace Sax.Helpers |
| { |
| /// <summary> |
| /// Base class for deriving an XML filter. |
| /// <para/> |
| /// <em>This module, both source code and documentation, is in the |
| /// Public Domain, and comes with <strong>NO WARRANTY</strong>.</em> |
| /// See <a href='http://www.saxproject.org'>http://www.saxproject.org</a> |
| /// for further information. |
| /// <para/> |
| /// This class is designed to sit between an <see cref="IXMLReader" /> |
| /// and the client application's event handlers. By default, it |
| /// does nothing but pass requests up to the reader and events |
| /// on to the handlers unmodified, but subclasses can override |
| /// specific methods to modify the event stream or the configuration |
| /// requests as they pass through. |
| /// </summary> |
| /// <seealso cref="IXMLFilter" /> |
| /// <seealso cref="IXMLReader" /> |
| /// <seealso cref="IEntityResolver" /> |
| /// <seealso cref="IDTDHandler" /> |
| /// <seealso cref="IContentHandler" /> |
| /// <seealso cref="IErrorHandler" /> |
| public class XMLFilter : IXMLFilter, IEntityResolver, IDTDHandler, IContentHandler, IErrorHandler |
| { |
| /// <summary> |
| /// Construct an empty XML filter, with no parent. |
| /// <para> |
| /// This filter will have no parent: you must assign a parent |
| /// before you start a parse or do any configuration with |
| /// setFeature or setProperty, unless you use this as a pure event |
| /// consumer rather than as an <see cref="IXMLReader" />. |
| /// </para> |
| /// </summary> |
| /// <seealso cref="IXMLReader.SetFeature" /> |
| /// <seealso cref="IXMLReader.SetProperty" /> |
| /// <seealso cref="Parent" /> |
| public XMLFilter() |
| { |
| } |
| |
| /// <summary> |
| /// Construct an XML filter with the specified parent. |
| /// </summary> |
| /// <param name="parent">The parent</param> |
| /// <seealso cref="Parent" /> |
| public XMLFilter(IXMLReader parent) |
| { |
| this.parent = parent; |
| } |
| |
| //////////////////////////////////////////////////////////////////// |
| // Implementation of IXMLFilter. |
| //////////////////////////////////////////////////////////////////// |
| |
| /// <summary> |
| /// Gets or sets the parent reader. |
| /// </summary> |
| /// <remarks> |
| /// This is the <see cref="IXMLReader"/> from which |
| /// this filter will obtain its events and to which it will pass its |
| /// configuration requests. The parent may itself be another filter. |
| /// <para/> |
| /// If there is no parent reader set, any attempt to parse |
| /// or to set or get a feature or property will fail. |
| /// </remarks> |
| public IXMLReader Parent |
| { |
| get => parent; |
| set => parent = value; |
| } |
| |
| //////////////////////////////////////////////////////////////////// |
| // Implementation of IXMLReader. |
| //////////////////////////////////////////////////////////////////// |
| |
| /// <summary> |
| /// Set the value of a feature. |
| /// <para/> |
| /// This will always fail if the parent is null. |
| /// </summary> |
| /// <param name="name">The feature name.</param> |
| /// <param name="value">The requested feature value.</param> |
| /// <exception cref="SAXNotRecognizedException">If the feature |
| /// value can't be assigned or retrieved from the parent.</exception> |
| /// <exception cref="SAXNotSupportedException">When the |
| /// parent recognizes the feature name but |
| /// cannot set the requested value.</exception> |
| public virtual void SetFeature(string name, bool value) |
| { |
| if (parent != null) |
| { |
| parent.SetFeature(name, value); |
| } |
| else |
| { |
| throw new SAXNotRecognizedException("Feature: " + name); |
| } |
| } |
| |
| /// <summary> |
| /// Look up the value of a feature. |
| /// <para/> |
| /// This will always fail if the parent is null. |
| /// </summary> |
| /// <param name="name">The feature name.</param> |
| /// <returns>The current value of the feature.</returns> |
| /// <exception cref="SAXNotRecognizedException">If the feature |
| /// value can't be assigned or retrieved from the parent.</exception> |
| /// <exception cref="SAXNotSupportedException">When the |
| /// parent recognizes the feature name but |
| /// cannot determine its value at this time.</exception> |
| public virtual bool GetFeature(string name) |
| { |
| if (parent != null) |
| { |
| return parent.GetFeature(name); |
| } |
| throw new SAXNotRecognizedException("Feature: " + name); |
| } |
| |
| /// <summary> |
| /// Set the value of a property. |
| /// <para/> |
| /// This will always fail if the parent is null. |
| /// </summary> |
| /// <param name="name">The property name.</param> |
| /// <param name="value">The requested property value.</param> |
| /// <exception cref="SAXNotRecognizedException">If the property |
| /// value can't be assigned or retrieved from the parent.</exception> |
| /// <exception cref="SAXNotSupportedException">When the |
| /// parent recognizes the property name but |
| /// cannot set the requested value.</exception> |
| public virtual void SetProperty(string name, object value) |
| { |
| if (parent != null) |
| { |
| parent.SetProperty(name, value); |
| } |
| else |
| { |
| throw new SAXNotRecognizedException("Property: " + name); |
| } |
| } |
| |
| /// <summary> |
| /// Look up the value of a property. |
| /// </summary> |
| /// <param name="name">The property name.</param> |
| /// <returns>The current value of the property.</returns> |
| /// <exception cref="SAXNotRecognizedException">If the property |
| /// value can't be assigned or retrieved from the parent.</exception> |
| /// <exception cref="SAXNotSupportedException">When the |
| /// parent recognizes the property name but |
| /// cannot determine its value at this time.</exception> |
| public virtual object GetProperty(string name) |
| { |
| if (parent != null) |
| { |
| return parent.GetProperty(name); |
| } |
| throw new SAXNotRecognizedException("Property: " + name); |
| } |
| |
| /// <summary> |
| /// Gets or Sets the entity resolver. |
| /// </summary> |
| public IEntityResolver EntityResolver |
| { |
| get => entityResolver; |
| set => entityResolver = value; |
| } |
| |
| /// <summary> |
| /// Gets or Sets the DTD event handler. |
| /// </summary> |
| public IDTDHandler DTDHandler |
| { |
| get => dtdHandler; |
| set => dtdHandler = value; |
| } |
| |
| /// <summary> |
| /// Gets or Sets the content event handler. |
| /// </summary> |
| public IContentHandler ContentHandler |
| { |
| get => contentHandler; |
| set => contentHandler = value; |
| } |
| |
| /// <summary> |
| /// Gets or Sets the error event handler. |
| /// </summary> |
| public IErrorHandler ErrorHandler |
| { |
| get => errorHandler; |
| set => errorHandler = value; |
| } |
| |
| /// <summary> |
| /// Parse an XML document. |
| /// <para> |
| /// The application can use this method to instruct the XML |
| /// reader to begin parsing an XML document from any valid input |
| /// source (a character stream, a byte stream, or a URI). |
| /// </para> |
| /// <para> |
| /// Applications may not invoke this method while a parse is in |
| /// progress (they should create a new XMLReader instead for each |
| /// nested XML document). Once a parse is complete, an |
| /// application may reuse the same XMLReader object, possibly with a |
| /// different input source. |
| /// Configuration of the XMLReader object (such as handler bindings and |
| /// values established for feature flags and properties) is unchanged |
| /// by completion of a parse, unless the definition of that aspect of |
| /// the configuration explicitly specifies other behavior. |
| /// (For example, feature flags or properties exposing |
| /// characteristics of the document being parsed.) |
| /// </para> |
| /// <para> |
| /// During the parse, the XMLReader will provide information |
| /// about the XML document through the registered event |
| /// handlers. |
| /// </para> |
| /// <para> |
| /// This method is synchronous: it will not return until parsing |
| /// has ended. If a client application wants to terminate |
| /// parsing early, it should throw an exception. |
| /// </para> |
| /// </summary> |
| /// <param name="input"> |
| /// The input source for the top-level of the |
| /// XML document. |
| /// </param> |
| /// <exception cref="SAXException"> |
| /// Any SAX exception, possibly |
| /// wrapping another exception. |
| /// </exception> |
| /// <exception cref="IOException"> |
| /// An IO exception from the parser, |
| /// possibly from a byte stream or character stream |
| /// supplied by the application. |
| /// </exception> |
| /// <seealso cref="InputSource" /> |
| /// <seealso cref="Parse(string)" /> |
| /// <seealso cref="IEntityResolver" /> |
| /// <seealso cref="IDTDHandler" /> |
| /// <seealso cref="IContentHandler" /> |
| /// <seealso cref="IErrorHandler" /> |
| public virtual void Parse(InputSource input) |
| { |
| SetupParse(); |
| parent.Parse(input); |
| } |
| |
| /// <summary> |
| /// Parse a document. |
| /// </summary> |
| /// <param name="systemId">The system identifier as a fully-qualified URI.</param> |
| /// <exception cref="SAXException">Any SAX exception, possibly |
| /// wrapping another exception.</exception> |
| /// <exception cref="IOException">An IO exception from the parser, |
| /// possibly from a byte stream or character stream |
| /// supplied by the application.</exception> |
| public virtual void Parse(string systemId) |
| { |
| Parse(new InputSource(systemId)); |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////// |
| // Implementation of IEntityResolver. |
| //////////////////////////////////////////////////////////////////// |
| |
| /// <summary> |
| /// Filter an external entity resolution. |
| /// </summary> |
| /// <param name="publicId">The entity's public identifier, or null.</param> |
| /// <param name="systemId">The entity's system identifier.</param> |
| /// <returns>A new <see cref="InputSource"/> or null for the default.</returns> |
| /// <exception cref="SAXException">The client may throw |
| /// an exception during processing.</exception> |
| /// <exception cref="IOException">The client may throw an |
| /// I/O-related exception while obtaining the |
| /// new <see cref="InputSource"/>.</exception> |
| public virtual InputSource ResolveEntity(string publicId, string systemId) |
| { |
| if (entityResolver != null) |
| { |
| return entityResolver.ResolveEntity(publicId, systemId); |
| } |
| return null; |
| } |
| |
| //////////////////////////////////////////////////////////////////// |
| // Implementation of IDTDHandler. |
| //////////////////////////////////////////////////////////////////// |
| |
| /// <summary> |
| /// Filter a notation declaration event. |
| /// </summary> |
| /// <param name="name">The notation name.</param> |
| /// <param name="publicId">The notation's public identifier, or null.</param> |
| /// <param name="systemId">The notation's system identifier, or null.</param> |
| /// <seealso cref="SAXException">The client may throw |
| /// an exception during processing.</seealso> |
| public virtual void NotationDecl(string name, string publicId, string systemId) |
| { |
| if (dtdHandler != null) |
| { |
| dtdHandler.NotationDecl(name, publicId, systemId); |
| } |
| } |
| |
| /// <summary> |
| /// Filter an unparsed entity declaration event. |
| /// </summary> |
| /// <param name="name">The entity name.</param> |
| /// <param name="publicId">The entity's public identifier, or null.</param> |
| /// <param name="systemId">The entity's system identifier, or null.</param> |
| /// <param name="notationName">The name of the associated notation.</param> |
| /// <exception cref="SAXException">The client may throw |
| /// an exception during processing.</exception> |
| public virtual void UnparsedEntityDecl(string name, string publicId, string systemId, string notationName) |
| { |
| if (dtdHandler != null) |
| { |
| dtdHandler.UnparsedEntityDecl(name, publicId, systemId, notationName); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////// |
| // Implementation of IContentHandler. |
| //////////////////////////////////////////////////////////////////// |
| |
| /// <summary> |
| /// Filter a new document locator event. |
| /// </summary> |
| /// <param name="locator">The document locator.</param> |
| public virtual void SetDocumentLocator(ILocator locator) |
| { |
| this.locator = locator; |
| if (contentHandler != null) |
| { |
| contentHandler.SetDocumentLocator(locator); |
| } |
| } |
| |
| /// <summary> |
| /// Filter a start document event. |
| /// </summary> |
| /// <exception cref="SAXException">The client may throw |
| /// an exception during processing.</exception> |
| public virtual void StartDocument() |
| { |
| if (contentHandler != null) |
| { |
| contentHandler.StartDocument(); |
| } |
| } |
| |
| /// <summary> |
| /// Filter an end document event. |
| /// </summary> |
| /// <exception cref="SAXException">The client may throw |
| /// an exception during processing.</exception> |
| public virtual void EndDocument() |
| { |
| if (contentHandler != null) |
| { |
| contentHandler.EndDocument(); |
| } |
| } |
| |
| /// <summary> |
| /// Filter a start Namespace prefix mapping event. |
| /// </summary> |
| /// <param name="prefix">The Namespace prefix.</param> |
| /// <param name="uri">The Namespace URI.</param> |
| /// <exception cref="SAXException">The client may throw |
| /// an exception during processing.</exception> |
| public virtual void StartPrefixMapping(string prefix, string uri) |
| { |
| if (contentHandler != null) |
| { |
| contentHandler.StartPrefixMapping(prefix, uri); |
| } |
| } |
| |
| /// <summary> |
| /// Filter an end Namespace prefix mapping event. |
| /// </summary> |
| /// <param name="prefix">The Namespace prefix.</param> |
| /// <exception cref="SAXException">The client may throw |
| /// an exception during processing.</exception> |
| public virtual void EndPrefixMapping(string prefix) |
| { |
| if (contentHandler != null) |
| { |
| contentHandler.EndPrefixMapping(prefix); |
| } |
| } |
| |
| /// <summary> |
| /// Filter a start element event. |
| /// </summary> |
| /// <param name="uri">The element's Namespace URI, or the empty string.</param> |
| /// <param name="localName">The element's local name, or the empty string.</param> |
| /// <param name="qName">The element's qualified (prefixed) name, or the empty string.</param> |
| /// <param name="atts">The element's attributes.</param> |
| /// <exception cref="SAXException">The client may throw |
| /// an exception during processing.</exception> |
| public virtual void StartElement(string uri, string localName, string qName, IAttributes atts) |
| { |
| if (contentHandler != null) |
| { |
| contentHandler.StartElement(uri, localName, qName, atts); |
| } |
| } |
| |
| /// <summary> |
| /// Filter an end element event. |
| /// </summary> |
| /// <param name="uri">The element's Namespace URI, or the empty string.</param> |
| /// <param name="localName">The element's local name, or the empty string.</param> |
| /// <param name="qName">The element's qualified (prefixed) name, or the empty string.</param> |
| /// <exception cref="SAXException">The client may throw |
| /// an exception during processing.</exception> |
| public virtual void EndElement(string uri, string localName, string qName) |
| { |
| if (contentHandler != null) |
| { |
| contentHandler.EndElement(uri, localName, qName); |
| } |
| } |
| |
| /// <summary> |
| /// Filter a character data event. |
| /// </summary> |
| /// <param name="ch">An array of characters.</param> |
| /// <param name="start">The starting position in the array.</param> |
| /// <param name="length">The number of characters to use from the array.</param> |
| /// <exception cref="SAXException">The client may throw |
| /// an exception during processing.</exception> |
| public virtual void Characters(char[] ch, int start, int length) |
| { |
| if (contentHandler != null) |
| { |
| contentHandler.Characters(ch, start, length); |
| } |
| } |
| |
| /// <summary> |
| /// Filter an ignorable whitespace event. |
| /// </summary> |
| /// <param name="ch">An array of characters.</param> |
| /// <param name="start">The starting position in the array.</param> |
| /// <param name="length">The number of characters to use from the array.</param> |
| /// <exception cref="SAXException">The client may throw |
| /// an exception during processing.</exception> |
| public virtual void IgnorableWhitespace(char[] ch, int start, int length) |
| { |
| if (contentHandler != null) |
| { |
| contentHandler.IgnorableWhitespace(ch, start, length); |
| } |
| } |
| |
| /// <summary> |
| /// Filter a processing instruction event. |
| /// </summary> |
| /// <param name="target">The processing instruction target.</param> |
| /// <param name="data">The text following the target.</param> |
| /// <exception cref="SAXException">The client may throw |
| /// an exception during processing.</exception> |
| public virtual void ProcessingInstruction(string target, string data) |
| { |
| if (contentHandler != null) |
| { |
| contentHandler.ProcessingInstruction(target, data); |
| } |
| } |
| |
| /// <summary> |
| /// Filter a skipped entity event. |
| /// </summary> |
| /// <param name="name">The name of the skipped entity.</param> |
| /// <exception cref="SAXException">The client may throw |
| /// an exception during processing.</exception> |
| public virtual void SkippedEntity(string name) |
| { |
| if (contentHandler != null) |
| { |
| contentHandler.SkippedEntity(name); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////// |
| // Implementation of IErrorHandler. |
| //////////////////////////////////////////////////////////////////// |
| |
| /// <summary> |
| /// Filter a warning event. |
| /// </summary> |
| /// <param name="e">The warning as an exception.</param> |
| /// <exception cref="SAXException">The client may throw |
| /// an exception during processing.</exception> |
| public virtual void Warning(SAXParseException e) |
| { |
| if (errorHandler != null) |
| { |
| errorHandler.Warning(e); |
| } |
| } |
| |
| /// <summary> |
| /// Filter an error event. |
| /// </summary> |
| /// <param name="e">The error as an exception.</param> |
| /// <exception cref="SAXException">The client may throw |
| /// an exception during processing.</exception> |
| public virtual void Error(SAXParseException e) |
| { |
| if (errorHandler != null) |
| { |
| errorHandler.Error(e); |
| } |
| } |
| |
| /// <summary> |
| /// Filter a fatal error event. |
| /// </summary> |
| /// <param name="e">The error as an exception.</param> |
| /// <exception cref="SAXException">The client may throw |
| /// an exception during processing.</exception> |
| public virtual void FatalError(SAXParseException e) |
| { |
| if (errorHandler != null) |
| { |
| errorHandler.FatalError(e); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////// |
| // Internal methods. |
| //////////////////////////////////////////////////////////////////// |
| |
| /// <summary> |
| /// Set up before a parse. |
| /// <para/> |
| /// Before every parse, check whether the parent is |
| /// non-null, and re-register the filter for all of the |
| /// events. |
| /// </summary> |
| private void SetupParse() |
| { |
| if (parent == null) |
| { |
| throw new InvalidOperationException("No parent for filter"); |
| } |
| parent.EntityResolver = this; |
| parent.DTDHandler = this; |
| parent.ContentHandler = this; |
| parent.ErrorHandler = this; |
| } |
| |
| //////////////////////////////////////////////////////////////////// |
| // Internal state. |
| //////////////////////////////////////////////////////////////////// |
| |
| private IXMLReader parent = null; |
| private ILocator locator = null; |
| private IEntityResolver entityResolver = null; |
| private IDTDHandler dtdHandler = null; |
| private IContentHandler contentHandler = null; |
| private IErrorHandler errorHandler = null; |
| } |
| } |