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

aSaxon-B-9-0-0-8sources.api.Saxon.Api.XSLT.cs Maven / Gradle / Ivy

Go to download

The Apache Commons Codec package contains simple encoder and decoders for various formats such as Base64 and Hexadecimal. In addition to these widely used encoders and decoders, the codec package also maintains a collection of phonetic encoding utilities.

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 JPipelineConfiguration = [email protected];
using JCompilerInfo = net.sf.saxon.trans.CompilerInfo;
using net.sf.saxon;
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;


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) {
            JStreamSource source = new JStreamSource(uri.ToString());
            JAugmentedSource aug = JAugmentedSource.makeAugmentedSource(source);
            aug.setPleaseCloseAfterUse(true);
            PreparedStylesheet pss = (PreparedStylesheet)factory.newTemplates(aug, info);
            return new XsltExecutable(pss);
        }

        /// 
        /// 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.
        /// 
        /// 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.
        /// 
        /// 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;

        // 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());
            }
        }

        /// 
        /// 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));
            }
        }

        /// 
        /// 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) {
            try {
                controller.setOutputProperties(destination.GetOutputProperties());
                if (initialContextNode != null) {
                    JDocumentInfo doc = initialContextNode.getDocumentRoot();
                    controller.registerDocument(doc, doc.getBaseURI());
                }
                controller.transformDocument(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; }
        }


    }

    ///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);

    }

    class ResultDocumentHandlerWrapper : JOutputURIResolver {

        private IResultDocumentHandler handler;
        private Hashtable resultMap = new Hashtable();

        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();
            resultMap.Add(result, destination);
            return destination.GetResult();
        }

        public void close(JResult result) {
            XmlDestination destination = (XmlDestination)resultMap[result];
            destination.Close();
        }
    }






}

//
// 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