api.Saxon.Api.Xslt.cs Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of saxon Show documentation
Show all versions of saxon Show documentation
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.
//