All Downloads are FREE. Search and download functionalities are using the official Maven repository.

api.Saxon.Api.Xslt.cs Maven / Gradle / Ivy

Go to download

Saxon a complete and conformant implementation of the XSLT 2.0, XQuery 1.0, and XPath 2.0 Recommendations published on 23 January 2007 by W3C

The newest version!
using System;
using System.IO;
using System.Xml;
using System.Collections;
using JStreamSource = javax.xml.transform.stream.StreamSource;
using JResult = javax.xml.transform.Result;
using JTransformerException = javax.xml.transform.TransformerException;
using JOutputURIResolver = net.sf.saxon.OutputURIResolver;
using JAugmentedSource = net.sf.saxon.AugmentedSource;
using JConfiguration = net.sf.saxon.Configuration;
using JLocationProvider = [email protected];
using JPipelineConfiguration = [email protected];
using JSequenceWriter = [email protected];
using JReceiverOptions = [email protected];
using JCompilerInfo = net.sf.saxon.trans.CompilerInfo;
using net.sf.saxon;
using JItem = net.sf.saxon.om.Item;
using JNodeInfo = net.sf.saxon.om.NodeInfo;
using JDocumentInfo = net.sf.saxon.om.DocumentInfo;
using JPullProvider = net.sf.saxon.pull.PullProvider;
using JPullSource = net.sf.saxon.pull.PullSource;
using JProcInstParser = net.sf.saxon.om.ProcInstParser;
using net.sf.saxon.dotnet;
using CharSequence = java.lang.CharSequence;


namespace Saxon.Api
{

    /// 
    /// An XsltCompiler object allows XSLT 2.0 stylesheets to be compiled.
    /// The compiler holds information that represents the static context
    /// for the compilation.
    /// 
    /// 
    /// To construct an XsltCompiler, use the factory method
    /// NewXsltCompiler on the Processor object.
    /// An XsltCompiler may be used repeatedly to compile multiple
    /// queries. Any changes made to the XsltCompiler (that is, to the
    /// static context) do not affect queries that have already been compiled.
    /// An XsltCompiler may be used concurrently in multiple threads, but
    /// it should not then be modified once initialized.
    /// 

    [Serializable]
    public class XsltCompiler
    {

        private TransformerFactoryImpl factory;
        private JConfiguration config;
        private JCompilerInfo info;
        private Uri baseUri;
        private IList errorList = null;

        // internal constructor: the public interface is a factory method
        // on the Processor object

        internal XsltCompiler(JConfiguration config)
        {
            this.factory = new TransformerFactoryImpl(config);
            this.config = config;
            this.info = new JCompilerInfo();
            info.setURIResolver(config.getURIResolver());
            info.setErrorListener(config.getErrorListener());
        }

        /// 
        /// The base URI of the stylesheet, which forms part of the static context
        /// of the stylesheet. This is used for resolving any relative URIs appearing
        /// within the stylesheet, for example in xsl:include and xsl:import
        /// declarations, in schema locations defined to xsl:import-schema, 
        /// or as an argument to the document() or doc() function.
        /// 
        /// 
        /// This base URI is used only if the input supplied to the Compile method
        /// does not provide its own base URI. It is therefore used on the version of the
        /// method that supplies input from a Stream. On the version that supplies
        /// input from an XmlReader, this base URI is used only if the XmlReader
        /// does not have its own base URI.
        /// 


        public Uri BaseUri
        {
            get { return baseUri; }
            set { baseUri = value; }
        }

        /// 
        /// An XmlResolver, which will be used to resolve URI references while compiling
        /// a stylesheet
        /// 
        /// 
        /// If no XmlResolver is set for the XsltCompiler, the XmlResolver
        /// is used that was set on the Processor at the time NewXsltCompiler
        /// was called.
        /// 

        public XmlResolver XmlResolver
        {
            get
            {
                return ((DotNetURIResolver)info.getURIResolver()).getXmlResolver();
            }
            set
            {
                info.setURIResolver(new DotNetURIResolver(value));
            }
        }

        /// 
        /// List of errors. The caller should supply an empty list before calling Compile;
        /// the processor will then populate the list with error information obtained during
        /// the compilation. Each error will be included as an object of type StaticError.
        /// If no error list is supplied by the caller, error information will be written to
        /// the standard error stream.
        /// 
        /// 
        /// By supplying a custom List with a user-written add() method, it is possible to
        /// intercept error conditions as they occur.
        /// 

        public IList ErrorList
        {
            set
            {
                errorList = value;
                info.setErrorListener(new ErrorGatherer(value));
            }
            get
            {
                return errorList;
            }
        }

        /// 
        /// Compile a stylesheet supplied as a Stream.
        /// 
        /// 
        /// 
        /// Stream source = new FileStream("input.xsl", FileMode.Open, FileAccess.Read);
        /// XsltExecutable q = compiler.Compile(source);
        /// source.Close();
        /// 
        /// 
        /// A stream containing the source text of the stylesheet
        /// An XsltExecutable which represents the compiled stylesheet object.
        /// The XsltExecutable may be loaded as many times as required, in the same or a different
        /// thread. The XsltExecutable is not affected by any changes made to the XsltCompiler
        /// once it has been compiled.
        /// 
        /// If the stylesheet contains any xsl:include or xsl:import declarations,
        /// then the BaseURI property must be set to allow these to be resolved.
        /// The stylesheet is contained in the part of the input stream between its current
        /// position and the end of the stream. It is the caller's responsibility to close the input 
        /// stream after use. If the compilation succeeded, then on exit the stream will be 
        /// exhausted; if compilation failed, the current position of the stream on exit is
        /// undefined.
        /// 

        public XsltExecutable Compile(Stream input)
        {
            JStreamSource ss = new JStreamSource(new DotNetInputStream(input));
            if (baseUri != null)
            {
                ss.setSystemId(baseUri.ToString());
            }
            PreparedStylesheet pss = (PreparedStylesheet)factory.newTemplates(ss, info);
            return new XsltExecutable(pss);
        }

        /// 
        /// Compile a stylesheet supplied as a TextReader.
        /// 
        /// 
        /// 
        /// String ss = "....]]>";
        /// TextReader source = new StringReader(ss);
        /// XsltExecutable q = compiler.Compile(source);
        /// source.Close();
        /// 
        /// 
        /// A TextReader containing the source text of the stylesheet
        /// An XsltExecutable which represents the compiled stylesheet object.
        /// The XsltExecutable may be loaded as many times as required, in the same or a different
        /// thread. The XsltExecutable is not affected by any changes made to the XsltCompiler
        /// once it has been compiled.
        /// 
        /// If the stylesheet contains any xsl:include or xsl:import declarations,
        /// then the BaseURI property must be set to allow these to be resolved.
        /// The stylesheet is contained in the part of the input stream between its current
        /// position and the end of the stream. It is the caller's responsibility to close the 
        /// TextReader after use. If the compilation succeeded, then on exit the stream will be 
        /// exhausted; if compilation failed, the current position of the stream on exit is
        /// undefined.
        /// 

        public XsltExecutable Compile(TextReader input)
        {
            JStreamSource ss = new JStreamSource(new DotNetReader(input));
            if (baseUri != null)
            {
                ss.setSystemId(baseUri.ToString());
            }
            PreparedStylesheet pss = (PreparedStylesheet)factory.newTemplates(ss, info);
            return new XsltExecutable(pss);
        }

        /// 
        /// Compile a stylesheet, retrieving the source using a URI.
        /// 
        /// 
        /// The document located via the URI is parsed using the System.Xml parser. This
        /// URI is used as the base URI of the stylesheet: the BaseUri property of the
        /// Compiler is ignored.
        /// 
        /// The URI identifying the location where the stylesheet document can be
        /// found
        /// An XsltExecutable which represents the compiled stylesheet object.
        /// The XsltExecutable may be run as many times as required, in the same or a different
        /// thread. The XsltExecutable is not affected by any changes made to the XsltCompiler
        /// once it has been compiled.

        public XsltExecutable Compile(Uri uri)
        {
            Object obj = XmlResolver.GetEntity(uri, "application/xml", Type.GetType("System.IO.Stream"));
            if (obj is Stream)
            {
                try
                {
                    XmlReader parser = new XmlTextReader(uri.ToString(), (Stream)obj);
                    ((XmlTextReader)parser).Normalization = true;
                    ((XmlTextReader)parser).WhitespaceHandling = WhitespaceHandling.All;
                    ((XmlTextReader)parser).XmlResolver = XmlResolver;
                    // Always need a validating parser, because that's the only way to get entity references expanded
                    parser = new XmlValidatingReader(parser);
                    ((XmlValidatingReader)parser).ValidationType = ValidationType.None;
                    JPullSource source = new JPullSource(new DotNetPullProvider(parser));
                    PreparedStylesheet pss = (PreparedStylesheet)factory.newTemplates(source, info);
                    return new XsltExecutable(pss);
                }
                finally
                {
                    ((Stream)obj).Close();
                }
            }
            else
            {
                throw new ArgumentException("Invalid type of result from XmlResolver.GetEntity: " + obj);
            }
        }

        /// 
        /// Compile a stylesheet, delivered using an XmlReader.
        /// 
        /// 
        /// The XmlReader is responsible for parsing the document; this method builds a tree
        /// representation of the document (in an internal Saxon format) and compiles it.
        /// If the XmlReader is an XmlTextReader, Saxon will set its Normalization
        /// property to true, and will wrap it in a (non-validating) XmlValidatingReader to ensure
        /// that entity references are expanded.
        /// 
        /// 
        /// If the XmlReader has a BaseUri property, then that property determines
        /// the base URI of the stylesheet module, which is used when resolving any xsl:include
        /// or xsl:import declarations. If the XmlReader has no BaseUri
        /// property, then the BaseUri property of the Compiler is used instead.
        /// An ArgumentNullException is thrown if this property has not been supplied.
        /// 
        /// The XmlReader (that is, the XML parser) used to supply the document containing
        /// the principal stylesheet module.
        /// An XsltExecutable which represents the compiled stylesheet object.
        /// The XsltExecutable may be run as many times as required, in the same or a different
        /// thread. The XsltExecutable is not affected by any changes made to the XsltCompiler
        /// once it has been compiled.


        public XsltExecutable Compile(XmlReader reader)
        {
            if (reader is XmlTextReader)
            {
                ((XmlTextReader)reader).Normalization = true;
                reader = new XmlValidatingReader(reader);
                ((XmlValidatingReader)reader).ValidationType = ValidationType.None;
            }
            DotNetPullProvider pp = new DotNetPullProvider(reader);
            JPipelineConfiguration pipe = config.makePipelineConfiguration();
            pipe.setLocationProvider(pp);
            pp.setPipelineConfiguration(pipe);
            // pp = new PullTracer(pp);  /* diagnostics */
            JPullSource source = new JPullSource(pp);
            String baseu = reader.BaseURI;
            if (baseu == null || baseu == String.Empty)
            {
                // if no baseURI is supplied by the XmlReader, use the one supplied to this Compiler
                if (baseUri == null)
                {
                    throw new ArgumentNullException("BaseUri");
                }
                baseu = baseUri.ToString();
                pp.setBaseURI(baseu);
            }
            source.setSystemId(baseu);
            PreparedStylesheet pss = (PreparedStylesheet)factory.newTemplates(source, info);
            return new XsltExecutable(pss);
        }

        /// 
        /// Compile a stylesheet, located at an XdmNode. This may be a document node whose
        /// child is an xsl:stylesheet or xsl:transform element, or it may be
        /// the xsl:stylesheet or xsl:transform element itself.
        /// 
        /// The document node or the outermost element node of the document
        /// containing the principal stylesheet module.
        /// An XsltExecutable which represents the compiled stylesheet object.
        /// The XsltExecutable may be run as many times as required, in the same or a different
        /// thread. The XsltExecutable is not affected by any changes made to the XsltCompiler
        /// once it has been compiled.

        public XsltExecutable Compile(XdmNode node)
        {
            PreparedStylesheet pss = (PreparedStylesheet)factory.newTemplates((JNodeInfo)node.value, info);
            return new XsltExecutable(pss);
        }

        /// Locate and compile a stylesheet identified by an <?xml-stylesheet?>
        /// processing instruction within a source document.
        /// 
        /// The document node of the source document containing the
        /// xml-stylesheet processing instruction.
        /// An XsltExecutable which represents the compiled stylesheet object.
        /// There are some limitations in the current implementation. The media type
        /// is ignored, as are the other parameters of the xml-stylesheet instruction. The
        /// href attribute must either reference an embedded stylesheet within the same
        /// document or a non-embedded external stylesheet.

        public XsltExecutable CompileAssociatedStylesheet(XdmNode source)
        {
            // TODO: lift the restrictions
            if (source == null || source.NodeKind != XmlNodeType.Document)
            {
                throw new ArgumentException("Source must be a document node");
            }
            IEnumerator kids = source.EnumerateAxis(XdmAxis.Child);
            QName xmlstyle = new QName("", "xml-stylesheet");
            while (kids.MoveNext())
            {
                XdmNode n = (XdmNode)kids.Current;
                if (n.NodeKind == XmlNodeType.ProcessingInstruction &&
                    n.NodeName.Equals(xmlstyle))
                {
                    // TODO: check the media type
                    String href = JProcInstParser.getPseudoAttribute(n.StringValue, "href");
                    if (href == null)
                    {
                        throw new DynamicError("xml-stylesheet processing instruction has no href attribute");
                    }
                    String fragment = null;
                    int hash = href.LastIndexOf('#');
                    if (hash == 0)
                    {
                        if (href.Length == 1)
                        {
                            throw new DynamicError("Relative URI of '#' is invalid");
                        }
                        fragment = href.Substring(1);
                        JNodeInfo target = ((JDocumentInfo)source.value).selectID(fragment);
                        XdmNode targetWrapper = null;
                        if (target == null)
                        {
                            // There's a problem here because the Microsoft XML parser doesn't
                            // report id values, so selectID() will never work. We work around that
                            // by looking for an attribute named "id" appearing on an xsl:stylesheet
                            // or xsl:transform element
                            QName qid = new QName("", "id");
                            IEnumerator en = source.EnumerateAxis(XdmAxis.Descendant);
                            while (en.MoveNext())
                            {
                                XdmNode x = (XdmNode)en.Current;
                                if (x.NodeKind == XmlNodeType.Element &&
                                        x.NodeName.Uri == "http://www.w3.org/1999/XSL/Transform" &&
                                        (x.NodeName.LocalName == "stylesheet" || x.NodeName.LocalName == "transform" &&
                                        x.GetAttributeValue(qid) == fragment))
                                {
                                    targetWrapper = x;
                                }
                            }
                        }
                        else
                        {
                            targetWrapper = (XdmNode)XdmValue.Wrap(target);
                        }
                        if (targetWrapper == null)
                        {
                            throw new DynamicError("No element with id='" + fragment + "' found");
                        }
                        return Compile(targetWrapper);
                    }
                    else if (hash > 0)
                    {
                        throw new NotImplementedException("href cannot identify an embedded stylesheet in a different document");
                    }
                    else
                    {
                        Uri uri = new Uri(n.BaseUri, href);
                        return Compile(uri);
                    }
                }
            }
            throw new DynamicError("xml-stylesheet processing instruction not found");
        }
    }

    /// 
    /// An XsltExecutable represents the compiled form of a stylesheet. To execute the stylesheet,
    /// it must first be loaded to form an XsltTransformer.
    /// 
    /// 
    /// An XsltExecutable is immutable, and therefore thread-safe. It is simplest to
    /// load a new XsltEvaluator each time the stylesheet is to be run. However, the 
    /// XsltEvaluator is serially reusable within a single thread.
    /// An XsltExecutable is created by using one of the Compile
    /// methods on the XsltCompiler class.
    ///     

    [Serializable]
    public class XsltExecutable
    {

        private PreparedStylesheet pss;

        // internal constructor

        internal XsltExecutable(PreparedStylesheet pss)
        {
            this.pss = pss;
        }

        /// 
        /// Load the stylesheet to prepare it for execution.
        /// 
        /// 
        /// An XsltTransformer. The returned XsltTransformer can be used to
        /// set up the dynamic context for stylesheet evaluation, and to run the stylesheet.
        /// 

        public XsltTransformer Load()
        {
            Controller c = (Controller)pss.newTransformer();
            return new XsltTransformer(c);
        }

    }

    /// 
    /// An XsltTransformer represents a compiled and loaded stylesheet ready for execution.
    /// The XsltTransformer holds details of the dynamic evaluation context for the stylesheet.
    /// 
    /// 
    /// An XsltTransformer should not be used concurrently in multiple threads. It is safe,
    /// however, to reuse the object within a single thread to run the same stylesheet several times.
    /// Running the stylesheet does not change the context that has been established.
    /// An XsltTransformer is always constructed by running the Load method of
    /// an XsltExecutable.
    ///      

    [Serializable]
    public class XsltTransformer
    {

        private Controller controller;
        private JNodeInfo initialContextNode;
        private IResultDocumentHandler resultDocumentHandler;
        private IMessageListener messageListener;
        private Stream traceFunctionDestination;
        

        // internal constructor

        internal XsltTransformer(Controller controller)
        {
            this.controller = controller;
        }

        /// 
        /// The initial context item for the stylesheet.
        /// 
        ///  This may be either a node or an atomic
        /// value. Most commonly it will be a document node, which might be constructed
        /// using the Build method of the DocumentBuilder object.
        /// 

        public XdmNode InitialContextNode
        {
            get { return (initialContextNode == null ? null : (XdmNode)XdmValue.Wrap(initialContextNode)); }
            set { initialContextNode = (value == null ? null : (JNodeInfo)value.Unwrap()); }
        }

        /// 
        /// The initial mode for the stylesheet. This is either a QName, for a 
        /// named mode, or null, for the unnamed (default) mode.
        /// 

        public QName InitialMode
        {
            get
            {
                String mode = controller.getInitialMode();
                if (mode == null)
                {
                    return null;
                }
                return QName.FromClarkName(mode);
            }
            set
            {
                controller.setInitialMode(value.ClarkName);
            }
        }

        /// 
        /// The initial template for the stylesheet. This is either a QName, for a 
        /// named template, or null, if no initial template has been set.
        /// 
        /// Setting this property to the name of a template
        /// that does not exist in the stylesheet throws a DynamicError with error 
        /// code XTDE0040. Setting it to the name of a template that has template
        /// parameters throws a DynamicError with error code XTDE0060.

        public QName InitialTemplate
        {
            get
            {
                String name = controller.getInitialTemplate();
                if (name == null)
                {
                    return null;
                }
                return QName.FromClarkName(name);
            }
            set
            {
                try
                {
                    controller.setInitialTemplate(value.ClarkName);
                }
                catch (javax.xml.transform.TransformerException err)
                {
                    throw new DynamicError(err);
                }
            }
        }

        /// 
        /// The base output URI, which acts as the base URI for resolving the href
        /// attribute of xsl:result-document.
        /// 

        public Uri BaseOutputUri
        {
            get
            {
                return new Uri(controller.getBaseOutputURI());
            }
            set
            {
                controller.setBaseOutputURI(value.ToString());
            }
        }

        public RecoveryPolicy RecoveryPolicy
        {
            get
            {
                switch (controller.getRecoveryPolicy())
                {
                    case Configuration.RECOVER_SILENTLY:
                        return RecoveryPolicy.RecoverSilently;
                    case Configuration.RECOVER_WITH_WARNINGS:
                        return RecoveryPolicy.RecoverWithWarnings;
                    default: return RecoveryPolicy.DoNotRecover;
                }
            }
            set
            {
                controller.setRecoveryPolicy(
                    value == RecoveryPolicy.RecoverSilently ? Configuration.RECOVER_SILENTLY :
                    value == RecoveryPolicy.RecoverWithWarnings ? Configuration.RECOVER_WITH_WARNINGS :
                    Configuration.DO_NOT_RECOVER);
            }
        }


        /// 
        /// The XmlResolver to be used at run-time to resolve and dereference URIs
        /// supplied to the doc() and document() functions.
        /// 

        public XmlResolver InputXmlResolver
        {
            get
            {
                return ((DotNetURIResolver)controller.getURIResolver()).getXmlResolver();
            }
            set
            {
                controller.setURIResolver(new DotNetURIResolver(value));
            }
        }

        /// 
        /// The IResultDocumentHandler to be used at run-time to process the output
        /// produced by any xsl:result-document instruction with an href
        /// attribute.
        /// 
        /// 
        /// In the absence of a user-supplied result document handler, the href
        /// attribute of the xsl:result-document instruction must be a valid relative
        /// URI, which is resolved against the value of the BaseOutputUri property,
        /// and the resulting absolute URI must identify a writable resource (typically
        /// a file in filestore, using the file: URI scheme).
        /// 

        public IResultDocumentHandler ResultDocumentHandler
        {
            get
            {
                return resultDocumentHandler;
            }
            set
            {
                resultDocumentHandler = value;
                controller.setOutputURIResolver(new ResultDocumentHandlerWrapper(value));
            }
        }

        /// 
        /// Listener for messages output using <xsl:message>. 
        /// The caller may supply a message listener before calling Run;
        /// the processor will then invoke the listener once for each message generated during
        /// the transformation. Each message will be output as an object of type XdmNode
        /// representing a document node.
        /// If no message listener is supplied by the caller, message information will be written to
        /// the standard error stream.
        /// 
        /// 
        /// Each message is presented as an XML document node. Calling ToString()
        /// on the message object will usually generate an acceptable representation of the
        /// message.
        /// When the <xsl:message> instruction specifies terminate="yes",
        /// the message is first notified using this interface, and then an exception is thrown
        /// which terminates the transformation.
        /// 

        public IMessageListener MessageListener
        {
            set
            {
                messageListener = value;
                controller.setMessageEmitter(new MessageListenerProxy(value));
            }
            get
            {
                return messageListener;
            }
        }

        /// 
        /// Destination for output of messages using <trace()>. 
        /// If no message listener is supplied by the caller, message information will be written to
        /// the standard error stream.
        /// 
        /// 
        /// The supplied destination is ignored if a TraceListener is in use.
        /// 

        public Stream TraceFunctionDestination
        {
            set
            {
                traceFunctionDestination = value;
                controller.setTraceFunctionDestination(
                    new java.io.PrintStream(new DotNetOutputStream(value)));
            }
            get
            {
                return traceFunctionDestination;
            }
        }



        /// 
        /// Set the value of a stylesheet parameter.
        /// 
        /// The name of the parameter, expressed
        /// as a QName. If a parameter of this name has been declared in the
        /// stylesheet, the given value will be assigned to the variable. If the
        /// variable has not been declared, calling this method has no effect (it is
        /// not an error).
        /// The value to be given to the parameter.
        /// If the parameter declaration defines a required type for the variable, then
        /// this value will be converted in the same way as arguments to function calls
        /// (for example, numeric promotion is applied).

        public void SetParameter(QName name, XdmValue value)
        {
            controller.setParameter(name.ClarkName, value.Unwrap());
        }

        /// 
        /// Run the transformation, sending the result to a specified destination.
        /// 
        /// 
        /// The destination for the results of the stylesheet. The class XmlDestination
        /// is an abstraction that allows a number of different kinds of destination
        /// to be specified.
        /// 
        /// Throws a DynamicError if the transformation
        /// fails.

        public void Run(XmlDestination destination)
        {
            // TODO: This isn't an ideal way of running the stylesheet if it invokes xsl:strip-space: it's better to do the
            // whitespace stripping while building the tree.
            try
            {
                controller.setOutputProperties(destination.GetOutputProperties());
                if (initialContextNode != null)
                {
                    JDocumentInfo doc = initialContextNode.getDocumentRoot();
                    controller.registerDocument(doc, doc.getBaseURI());
                }
                controller.transform(initialContextNode, destination.GetResult());
                destination.Close();
            }
            catch (javax.xml.transform.TransformerException err)
            {
                throw new DynamicError(err);
            }
        }

        /// 
        /// Escape hatch to the underlying Java implementation
        /// 

        public Controller Implementation
        {
            get { return controller; }
        }


    }

    /// 
    /// RecoveryPolicy is an enumeration of the different actions that can be taken when a "recoverable error" occurs
    /// 

    public enum RecoveryPolicy
    {
        /// 
        /// Ignore the error, take the recovery action, do not produce any message
        /// 
        RecoverSilently,

        /// 
        /// Take the recovery action after outputting a warning message
        /// 
        RecoverWithWarnings,

        /// 
        /// Treat the error as fatal
        /// 
        DoNotRecover

    }



    ///An IResultDocumentHandler can be nominated to handle output
    /// produced by the xsl:result-document instruction in an XSLT stylesheet.
    ///
    ///
    ///This interface affects any xsl:result-document instruction
    /// executed by the stylesheet, provided that it has an href attribute. 
    ///If no IResultDocumentHandler is nominated (in the
    /// IResultDocumentHandler property of the XsltTransformer, the output
    /// of xsl:result-document is serialized, and is written to the file
    /// or other resource identified by the URI in the href attribute, resolved
    /// (if it is relative> against the URI supplied in the BaseOutputUri property
    /// of the XsltTransformer.
    ///If an IResultDocumentHandler is nominated, however, its
    /// HandleResultDocument method will be called whenever an xsl:result-document
    /// instruction with an href attribute is evaluated, and the generated result tree
    /// will be passed to the XmlDestination returned by that method. 
    ///

    public interface IResultDocumentHandler
    {

        ///  Handle output produced by the xsl:result-document
        /// instruction in an XSLT stylesheet. This method is called by the XSLT processor
        /// when an xsl:result-document with an href attribute is evaluated.
        /// 
        /// An absolute or relative URI. This will be the effective value of the 
        /// href attribute of the xsl:result-document in the stylesheet.
        /// The base URI that should be used for resolving the value of
        /// href if it is relative. This will always be the value of the BaseOutputUri
        /// property of the XsltTransformer.
        /// An XmlDestination to handle the result tree produced by the
        /// xsl:result-document instruction. The Close method of the returned
        /// XmlDestination will be called when the output is complete.
        /// 
        /// The XSLT processor will ensure that the stylesheet cannot create
        /// two distinct result documents which are sent to the same URI. It is the responsibility
        /// of the IResultDocumentHandler to ensure that two distinct result documents are
        /// not set to the same XmlDestination. Failure to observe this rule can result
        /// in output streams being incorrectly closed.
        /// 
        /// Note that more than one result document can be open at the same time,
        /// and that the order of opening, writing, and closing result documents chosen
        /// by the processor does not necessarily bear any direct resemblance to the way
        /// that the XSLT source code is written.

        XmlDestination HandleResultDocument(string href, Uri baseUri);

    }

    internal class ResultDocumentHandlerWrapper : JOutputURIResolver
    {

        private IResultDocumentHandler handler;
        private ArrayList resultList = new ArrayList();
        private ArrayList destinationList = new ArrayList();

        public ResultDocumentHandlerWrapper(IResultDocumentHandler handler)
        {
            this.handler = handler;
        }

        public JResult resolve(String href, String baseString)
        {
            Uri baseUri;
            try
            {
                baseUri = new Uri(baseString);
            }
            catch (System.UriFormatException err)
            {
                throw new JTransformerException("Invalid base output URI " + baseString, err);
            }
            XmlDestination destination = handler.HandleResultDocument(href, baseUri);
            JResult result = destination.GetResult();
            resultList.Add(result);
            destinationList.Add(destination);
            return result;
        }

        public void close(JResult result)
        {
            for (int i = 0; i < resultList.Count; i++)
            {
                if (Object.ReferenceEquals(resultList[i], result))
                {
                    ((XmlDestination)destinationList[i]).Close();
                    resultList.RemoveAt(i);
                    destinationList.RemoveAt(i);
                    return;
                }
            }
        }
    }

    ///An IMessageListener can be nominated to handle output
    /// produced by the xsl:message instruction in an XSLT stylesheet.
    ///
    ///
    ///This interface affects any xsl:message instruction
    /// executed by the stylesheet. 
    ///If no IMessageListener is nominated (in the
    /// MessageListener property of the XsltTransformer), the output
    /// of xsl:message is serialized, and is written to standard error
    /// output stream.
    ///If an IMessageListener is nominated, however, its
    /// Message method will be called whenever an xsl:message
    /// instruction is evaluated. 
    ///


    public interface IMessageListener
    {

        ///Handle the output of an xsl:message instruction
        ///in the stylesheet
        ///
        ///

        void Message(XdmNode content, bool terminate, IXmlLocation location);

    }

    /// 
    /// An IXmlLocation represents the location of a node within an XML document.
    /// It is in two parts: the base URI (or system ID) of the external entity (which will usually
    /// be the XML document entity itself), and the line number of a node relative
    /// to the base URI of the containing external entity.
    /// 
    /// 

    public interface IXmlLocation
    {

        /// 
        /// The base URI (system ID) of an external entity within an XML document.
        /// Set to null if the base URI is not known (for example, for an XML document
        /// created programmatically where no base URI has been set up).
        /// 

        Uri BaseUri { get; set; }

        /// 
        /// The line number of a node relative to the start of the external entity.
        /// The value -1 indicates that the line number is not known or not applicable.
        /// 

        int LineNumber { get; set; }
    }

    internal class XmlLocation : IXmlLocation
    {
        private Uri baseUri;
        private int lineNumber;
        public Uri BaseUri
        {
            get { return baseUri; }
            set { baseUri = value; }
        }
        public int LineNumber
        {
            get { return lineNumber; }
            set { lineNumber = value; }
        }
    }


    [Serializable]
    internal class MessageListenerProxy : JSequenceWriter
    {

        public IMessageListener listener;
        public bool terminate;
        public int locationId;

        public MessageListenerProxy(IMessageListener ml)
        {
            listener = ml;
        }

        public override void startDocument(int properties)
        {
            terminate = (properties & JReceiverOptions.TERMINATE) != 0;
            locationId = -1;
            base.startDocument(properties);
        }

        public override void startElement(int nameCode, int typeCode, int locationId, int properties)
        {
            if (this.locationId == -1)
            {
                this.locationId = locationId;
            }
            base.startElement(nameCode, typeCode, locationId, properties);
        }

        public override void characters(CharSequence s, int locationId, int properties)
        {
            if (this.locationId == -1)
            {
                this.locationId = locationId;
            }
            base.characters(s, locationId, properties);
        }

        public override void append(JItem item, int locationId, int copyNamespaces)
        {
            if (this.locationId == -1)
            {
                this.locationId = locationId;
            }
            base.append(item, locationId, copyNamespaces);
        }

        public override void write(JItem item)
        {
            XmlLocation loc = new XmlLocation();
            if (locationId != -1)
            {
                JLocationProvider provider = getPipelineConfiguration().getLocationProvider();
                loc.BaseUri = new Uri(provider.getSystemId(locationId));
                loc.LineNumber = provider.getLineNumber(locationId);
            }
            listener.Message((XdmNode)XdmItem.Wrap(item), terminate, loc);
        }
    }


}

//
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
// you may not use this file except in compliance with the License. You may obtain a copy of the
// License at http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
// See the License for the specific language governing rights and limitations under the License.
//
// The Original Code is: all this file.
//
// The Initial Developer of the Original Code is Michael H. Kay.
//
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
//
// Contributor(s): none.
//




© 2015 - 2024 Weber Informatics LLC | Privacy Policy