api.Saxon.Api.Model.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 JConfiguration = net.sf.saxon.Configuration;
using JAtomicValue = net.sf.saxon.value.AtomicValue;
using JEmptySequence = net.sf.saxon.value.EmptySequence;
using JSingletonNode = net.sf.saxon.value.SingletonNode;
using JConversionResult = net.sf.saxon.type.ConversionResult;
using JValidationFailure = net.sf.saxon.type.ValidationFailure;
using JStandardNames = net.sf.saxon.om.StandardNames;
using DotNetReceiver = net.sf.saxon.dotnet.DotNetReceiver;
using DotNetObjectValue = net.sf.saxon.dotnet.DotNetObjectValue;
using JBigDecimal = java.math.BigDecimal;
using JArrayList = java.util.ArrayList;
using net.sf.saxon.om;
using net.sf.saxon.value;
using net.sf.saxon.pattern;
using JAtomicType = net.sf.saxon.type.AtomicType;
using JSchemaType = net.sf.saxon.type.SchemaType;
using JType = net.sf.saxon.type.Type;
namespace Saxon.Api
{
///
/// An value in the XDM data model. A value is a sequence of zero or more
/// items, each item being either an atomic value or a node.
///
///
/// An XdmValue is immutable.
/// A sequence consisting of a single item may be represented
/// as an instance of XdmItem , which is a subtype of XdmValue .
///
[Serializable]
public class XdmValue : IEnumerable
{
internal ValueRepresentation value;
internal XdmValue() { }
///
/// Create a value from a collection of items
///
/// An enumerable collection providing the items to make up the sequence. Every
/// member of this collection must be an instance of XdmItem
///
public XdmValue(IEnumerable items)
{
JArrayList list = new JArrayList();
foreach (XdmItem c in items)
{
list.add((Item)c.Unwrap());
}
value = new SequenceExtent(list);
}
///
/// Create an XdmValue from an underlying Saxon ValueRepresentation object.
/// This method is provided for the benefit of applications that need to mix
/// use of the Saxon .NET API with direct use of the underlying objects
/// and methods offered by the Java implementation.
///
/// An object representing an XDM value in the
/// underlying Saxon implementation.
/// An XdmValue that wraps the underlying Saxon value
/// representation.
public static XdmValue Wrap(ValueRepresentation value)
{
XdmValue result;
if (value == null || value is JEmptySequence)
{
return XdmEmptySequence.INSTANCE;
}
else if (value is JAtomicValue)
{
result = new XdmAtomicValue();
}
else if (value is NodeInfo)
{
result = new XdmNode();
}
else if (value is JSingletonNode)
{
value = ((JSingletonNode)value).getNode();
result = new XdmNode();
}
else
{
result = new XdmValue();
}
result.value = value;
return result;
}
///
/// Extract the underlying Saxon ValueRepresentation object from an XdmValue.
/// This method is provided for the benefit of applications that need to mix
/// use of the Saxon .NET API with direct use of the underlying objects
/// and methods offered by the Java implementation.
///
/// An object representing the XDM value in the
/// underlying Saxon implementation.
public ValueRepresentation Unwrap()
{
return value;
}
///
/// Get the sequence of items in the form of an IList
///
///
/// The list of items making up this value. Each item in the list
/// will be an object of type XdmItem
///
public IList GetList()
{
if (value == null)
{
return new ArrayList();
}
else if (value is Item)
{
ArrayList list = new ArrayList(1);
list.Add((NodeInfo)value);
return list;
}
else
{
ArrayList list = new ArrayList();
SequenceIterator iter = ((Value)value).iterate();
while (true)
{
Item jitem = iter.next();
if (jitem == null)
{
break;
}
list.Add((XdmItem)XdmValue.Wrap(jitem));
}
return list;
}
}
///
/// Get the sequence of items in the form of an IEnumerator
///
///
/// An enumeration over the list of items making up this value. Each item in the list
/// will be an object of type XdmItem
///
public IEnumerator GetEnumerator()
{
if (value == null)
{
return EmptyEnumerator.INSTANCE;
}
else if (value is Item)
{
return new SequenceEnumerator(SingletonIterator.makeIterator((Item)value));
}
else
{
return new SequenceEnumerator(((Value)value).iterate());
}
}
///
/// Get the number of items in the sequence
///
///
/// The number of items in the sequence
///
public int Count
{
get
{
if (value == null)
{
return 0;
}
else if (value is Item)
{
return 1;
}
else
{
return ((Value)value).getLength();
}
}
}
}
///
/// The class XdmItem represents an item in a sequence, as defined
/// by the XDM data model. An item is either an atomic value or a node.
///
///
/// An item is a member of a sequence, but it can also be considered as
/// a sequence (of length one) in its own right. XdmItem is a subtype
/// of XdmValue because every Item in the XDM data model is also a
/// value.
/// It cannot be assumed that every sequence of length one will be
/// represented by an XdmItem . It is quite possible for an XdmValue
/// that is not an XdmItem to hold a singleton sequence.
///
[Serializable]
public abstract class XdmItem : XdmValue
{
///
/// Determine whether the item is an atomic value
///
///
/// true if the item is an atomic value, false if it is a Node
///
public abstract bool IsAtomic();
}
///
/// The class XdmAtomicValue represents an item in an XPath 2.0 sequence
/// that is an atomic value. The value may belong to any of the 19 primitive types
/// defined in XML Schema, or to a type derived from these primitive types, or to
/// the XPath 2.0 type xdt:untypedAtomic
///
[Serializable]
public class XdmAtomicValue : XdmItem
{
//internal JAtomicValue atomicValue;
internal XdmAtomicValue() { }
///
/// Determine whether the item is an atomic value
///
///
/// true (the item is an atomic value)
///
public override bool IsAtomic()
{
return true;
}
//internal AtomicValue(JAtomicValue value) {
// this.value = value;
//}
///
/// Construct an atomic value of type xs:string
///
/// The string value
public XdmAtomicValue(String str)
{
this.value = new StringValue(str);
}
///
/// Construct an atomic value of type xs:integer
///
/// The integer value
public XdmAtomicValue(long i)
{
this.value = new Int64Value(i);
}
///
/// Construct an atomic value of type xs:decimal
///
/// The decimal value
public XdmAtomicValue(decimal d)
{
this.value = new DecimalValue(new JBigDecimal(d.ToString()));
}
///
/// Construct an atomic value of type xs:float
///
/// The float value
public XdmAtomicValue(float f)
{
this.value = new FloatValue(f);
}
///
/// Construct an atomic value of type xs:double
///
/// The double value
public XdmAtomicValue(double d)
{
this.value = new DoubleValue(d);
}
///
/// Construct an atomic value of type xs:boolean
///
/// The boolean value
public XdmAtomicValue(bool b)
{
this.value = BooleanValue.get(b);
}
///
/// Construct an atomic value of type xs:anyURI
///
/// The uri value
public XdmAtomicValue(Uri u)
{
this.value = new AnyURIValue(u.ToString());
}
///
/// Construct an atomic value of type xs:QName
///
/// The QName value
public XdmAtomicValue(QName q)
{
this.value = new QNameValue(
q.Prefix, q.Uri, q.LocalName);
}
///
/// Construct an atomic value of a given built-in or user-defined type
///
///
/// AtomicValue("abcd", QName.XDT_UNTYPED_ATOMIC)
/// creates an untyped atomic value containing the string "abcd"
///
/// The string representation of the value (any value that is acceptable
/// in the lexical space, as defined by XML Schema Part 2). Whitespace normalization as defined by
/// the target type will be applied to the value.
/// The QName giving the name of the target type. This must be an atomic
/// type, and it must not be a type that is namespace-sensitive (QName, NOTATION, or types derived
/// from these). If the type is a user-defined type then its definition must be present
/// in the schema cache maintained by the SchemaManager .
/// The Processor object. This is needed for looking up user-defined
/// types, and also because some conversions are context-sensitive, for example they depend on the
/// implicit timezone or the choice of XML 1.0 versus XML 1.1 for validating names.
/// Thrown if the type is unknown or unsuitable, or if the supplied string is not
/// a valid lexical representation of a value of the given type.
public XdmAtomicValue(String lexicalForm, QName type, Processor processor)
{
JConfiguration jconfig = processor.config;
int fp = jconfig.getNamePool().getFingerprint(type.Uri, type.LocalName);
if (fp == -1)
{
throw new ArgumentException("Unknown name " + type);
}
JSchemaType st = jconfig.getSchemaType(fp);
if (st == null)
{
throw new ArgumentException("Unknown type " + type);
}
if (!(st is JAtomicType))
{
throw new ArgumentException("Specified type " + type + " is not atomic");
}
if (((JAtomicType)st).isNamespaceSensitive())
{
throw new ArgumentException("Specified type " + type + " is namespace-sensitive");
}
JConversionResult result = new StringValue(lexicalForm).convert(
(JAtomicType)st,
true,
jconfig.getConversionContext());
if (result is JValidationFailure)
{
throw new ArgumentException(((JValidationFailure)result).getMessage());
}
this.value = (JAtomicValue)result;
}
///
/// Create an atomic value that wraps an external object. Such values can be used
/// in conjunction with extension functions. (Synonym of WrapExternalObject ,
/// retained for backwards compatibility.)
///
/// The object to be wrapped.
/// The wrapped object
public static XdmAtomicValue wrapExternalObject(object external)
{
return (XdmAtomicValue)XdmValue.Wrap(new DotNetObjectValue(external));
}
///
/// Create an atomic value that wraps an external object. Such values can be used
/// in conjunction with extension functions.
///
/// The object to be wrapped.
/// The wrapped object
public static XdmAtomicValue WrapExternalObject(object external)
{
return (XdmAtomicValue)XdmValue.Wrap(new DotNetObjectValue(external));
}
///
/// Convert the atomic value to a string
///
/// The value converted to a string, according to the rules
/// of the XPath 2.0 cast operator
public override String ToString()
{
return ((JAtomicValue)value).getStringValue();
}
///
/// Get the name of the value's XDM type
///
/// The Processor object.
/// This is needed for access to the NamePool,
/// which maps the internal form of type names to their external form.
/// The type of the value, as a QName. This may be a built-in type or a user-defined
/// atomic type.
///
public QName GetTypeName(Processor processor)
{
int fp = ((JAtomicType)((JAtomicValue)value).getItemType(null)).getFingerprint();
NamePool pool = processor.config.getNamePool();
return new QName(pool.getPrefix(fp),
pool.getURI(fp),
pool.getLocalName(fp));
}
///
/// Get the name of the primitive type of the value
///
/// The primitive type of the value, as a QName. This will be the name of
/// one of the primitive types defined in XML Schema Part 2, or the XPath-defined
/// type xdt:untypedAtomic . For the purposes of this method, xs:integer is considered
/// to be a primitive type.
///
public QName GetPrimitiveTypeName()
{
int fp = ((JAtomicValue)value).getItemType(null).getPrimitiveType();
return new QName(JStandardNames.getPrefix(fp),
JStandardNames.getURI(fp),
JStandardNames.getLocalName(fp));
}
/// Get the value as a CLI object of the nearest equivalent type.
///
/// The return type is as follows:
/// xs:string - String
/// xs:integer - Long
/// xs:decimal - Decimal
/// xs:double - Double
/// xs:float - Float
/// xs:boolean - Bool
/// xs:QName - QName
/// xs:anyURI - Uri
/// xdt:untypedAtomic - String
/// Other types - currently String, but this may change in the future
///
/// The value converted to the most appropriate CLI type
public Object Value
{
get
{
if (value is IntegerValue)
{
return ((IntegerValue)value).longValue();
}
else if (value is DoubleValue)
{
return ((DoubleValue)value).getDoubleValue();
}
else if (value is FloatValue)
{
return ((FloatValue)value).getFloatValue();
}
else if (value is DecimalValue)
{
return Decimal.Parse(((DecimalValue)value).getStringValue());
}
else if (value is BooleanValue)
{
return ((BooleanValue)value).getBooleanValue();
}
else if (value is AnyURIValue)
{
return new Uri(((AnyURIValue)value).getStringValue());
}
else if (value is QNameValue)
{
return new QName((QNameValue)value);
}
else
{
return ((JAtomicValue)value).getStringValue();
}
}
}
}
///
/// The class XdmNode represents a Node in the XDM Data Model. A Node
/// is an XdmItem , and is therefore an XdmValue in its own right, and may also participate
/// as one item within a sequence value.
///
///
/// An XdmNode is implemented as a wrapper around an object
/// of type net.sf.saxon.NodeInfo . Because this is a key interface
/// within Saxon, it is exposed via this API, even though it is a Java
/// interface that is not part of the API proper.
/// The XdmNode interface exposes basic properties of the node, such
/// as its name, its string value, and its typed value. Navigation to other nodes
/// is supported through a single method, EnumerateAxis , which allows
/// other nodes to be retrieved by following any of the XPath axes.
///
[Serializable]
public class XdmNode : XdmItem
{
///
/// Determine whether the item is an atomic value
///
///
/// false (the item is not an atomic value)
///
public override bool IsAtomic()
{
return false;
}
///
/// The name of the node, as a QName . Returns null in the case of unnamed nodes.
///
public QName NodeName
{
get
{
NodeInfo node = (NodeInfo)value;
String local = node.getLocalPart();
if (local == "")
{
return null;
}
String prefix = node.getPrefix();
String uri = node.getURI();
return new QName(prefix, uri, local);
}
}
///
/// The kind of node, as an instance of System.Xml.XmlNodeType .
///
/// For a namespace node in the XDM model, the value XmlNodeType.None
/// is returned.
///
public XmlNodeType NodeKind
{
get
{
NodeInfo node = (NodeInfo)value;
int kind = node.getNodeKind();
switch (kind)
{
case JType.DOCUMENT:
return XmlNodeType.Document;
case JType.ELEMENT:
return XmlNodeType.Element;
case JType.ATTRIBUTE:
return XmlNodeType.Attribute;
case JType.TEXT:
return XmlNodeType.Text;
case JType.COMMENT:
return XmlNodeType.Comment;
case JType.PROCESSING_INSTRUCTION:
return XmlNodeType.ProcessingInstruction;
case JType.NAMESPACE:
return XmlNodeType.None;
default:
throw new ArgumentException("Unknown node kind");
}
}
}
///
/// The typed value of the node, as an instance of XdmValue .
///
///
/// A DynamicError is thrown if the node has no typed value, as will be the case for
/// an element with element-only content.
///
public XdmValue TypedValue
{
get { return XdmValue.Wrap(((NodeInfo)value).atomize()); }
}
///
/// The string value of the node.
///
public String StringValue
{
get { return ((NodeInfo)value).getStringValue(); }
}
///
/// Get the parent of this node.
///
///
/// Returns either a document node, and element node, or null in the case where
/// this node has no parent.
///
public XdmNode Parent
{
get { return (XdmNode)XdmValue.Wrap(((NodeInfo)value).getParent()); }
}
///
/// Get the root of the tree containing this node.
///
///
/// Returns the root of the tree containing this node (which might be this node itself).
///
public XdmNode Root
{
get
{
XdmNode parent = Parent;
if (parent == null)
{
return this;
}
else
{
return parent.Root;
}
}
}
///
/// Get a the string value of a named attribute of this element.
///
///
/// Returns null if this node is not an element, or if this element has no
/// attribute with the specified name.
///
/// The name of the attribute whose value is required
public String GetAttributeValue(QName name)
{
int fp = ((NodeInfo)value).getConfiguration().getNamePool().allocate(
"", name.Uri, name.LocalName);
return ((NodeInfo)value).getAttributeValue(fp);
}
///
/// Get an enumerator that supplies all the nodes on one of the XPath
/// axes, starting with this node.
///
///
/// The axis to be navigated, for example XdmAxis.Child for the child axis.
///
///
/// The nodes are returned in axis order: that is, document order for a forwards
/// axis, reverse document order for a reverse axis.
///
public IEnumerator EnumerateAxis(XdmAxis axis)
{
return new SequenceEnumerator(((NodeInfo)value).iterateAxis(GetAxisNumber(axis)));
}
///
/// Get an enumerator that selects all the nodes on one of the XPath
/// axes, provided they have a given name. The nodes selected are those of the principal
/// node kind (elements for most axes, attributes for the attribute axis, namespace nodes
/// for the namespace axis) whose name matches the name given in the second argument.
///
///
/// The axis to be navigated, for example XdmAxis.Child for the child axis.
///
///
/// The name of the required nodes, for example new QName("", "item") to select
/// nodes with local name "item", in no namespace.
///
///
/// The nodes are returned in axis order: that is, document order for a forwards
/// axis, reverse document order for a reverse axis.
///
public IEnumerator EnumerateAxis(XdmAxis axis, QName nodeName)
{
int kind;
switch (axis)
{
case XdmAxis.Attribute:
kind = net.sf.saxon.type.Type.ATTRIBUTE;
break;
case XdmAxis.Namespace:
kind = net.sf.saxon.type.Type.NAMESPACE;
break;
default:
kind = net.sf.saxon.type.Type.ELEMENT;
break;
}
NamePool pool = ((NodeInfo)value).getConfiguration().getNamePool();
int nameCode = pool.allocate("", nodeName.Uri, nodeName.LocalName);
NameTest test = new NameTest(kind, nameCode, pool);
return new SequenceEnumerator(((NodeInfo)value).iterateAxis(GetAxisNumber(axis), test));
}
private static byte GetAxisNumber(XdmAxis axis)
{
switch (axis)
{
case XdmAxis.Ancestor: return Axis.ANCESTOR;
case XdmAxis.AncestorOrSelf: return Axis.ANCESTOR_OR_SELF;
case XdmAxis.Attribute: return Axis.ATTRIBUTE;
case XdmAxis.Child: return Axis.CHILD;
case XdmAxis.Descendant: return Axis.DESCENDANT;
case XdmAxis.DescendantOrSelf: return Axis.DESCENDANT_OR_SELF;
case XdmAxis.Following: return Axis.FOLLOWING;
case XdmAxis.FollowingSibling: return Axis.FOLLOWING_SIBLING;
case XdmAxis.Namespace: return Axis.NAMESPACE;
case XdmAxis.Parent: return Axis.PARENT;
case XdmAxis.Preceding: return Axis.PRECEDING;
case XdmAxis.PrecedingSibling: return Axis.PRECEDING_SIBLING;
case XdmAxis.Self: return Axis.SELF;
}
return 0;
}
///
/// The Base URI of the node.
///
public Uri BaseUri
{
get { return new Uri(((NodeInfo)value).getBaseURI()); }
}
///
/// The Document URI of the node.
///
public Uri DocumentUri
{
get
{
String s = ((NodeInfo)value).getSystemId();
if (s == null || s.Length == 0)
{
return null;
}
return new Uri(s);
}
}
///
/// Send the node (that is, the subtree rooted at this node) to an XmlWriter
///
///
/// Note that a XmlWriter can only handle a well-formed XML document. This method
/// will therefore signal an exception if the node is a document node with no children, or with
/// more than one element child.
///
public void WriteTo(XmlWriter writer)
{
NodeInfo node = ((NodeInfo)value);
DotNetReceiver receiver = new DotNetReceiver(writer);
receiver.setPipelineConfiguration(node.getConfiguration().makePipelineConfiguration());
receiver.open();
node.copy(receiver, 2, false, 0);
receiver.close();
}
///
/// Return a serialization of this node as lexical XML
///
///
/// In the case of an element node, the result will be a well-formed
/// XML document serialized as defined in the W3C XSLT/XQuery serialization specification,
/// using options method="xml", indent="yes", omit-xml-declaration="yes".
/// In the case of a document node, the result will be a well-formed
/// XML document provided that the document node contains exactly one element child,
/// and no text node children. In other cases it will be a well-formed external
/// general parsed entity.
/// In the case of an attribute node, the output is a string in the form
/// name="value" . The name will use the original namespace prefix.
/// Other nodes, such as text nodes, comments, and processing instructions, are
/// represented as they would appear in lexical XML.
///
public String OuterXml
{
get
{
NodeInfo node = ((NodeInfo)value);
if (node.getNodeKind() == JType.ATTRIBUTE)
{
String val = node.getStringValue().Replace("\"", """);
val = val.Replace("<", "<");
val = val.Replace("&", "&");
return node.getDisplayName() + "=\"" + val + '"';
}
Serializer serializer = new Serializer();
serializer.SetOutputProperty(Serializer.METHOD, "xml");
serializer.SetOutputProperty(Serializer.INDENT, "yes");
serializer.SetOutputProperty(Serializer.OMIT_XML_DECLARATION, "yes");
StringWriter sw = new StringWriter();
serializer.SetOutputWriter(sw);
node.copy(serializer.GetReceiver(node.getConfiguration()), 2, false, 0);
return sw.ToString();
}
}
///
/// Return a string representation of the node.
///
///
/// This currently returns the same as the OuterXml property.
/// To get the string value as defined in XPath, use the StringValue property.
///
public override String ToString()
{
return OuterXml;
}
///
/// Escape hatch to the underlying class in the Java implementation
///
public NodeInfo Implementation
{
get { return ((NodeInfo)value); }
}
}
///
/// The class XdmEmptySequence represents an empty sequence in the XDM Data Model.
///
///
/// An empty sequence may also be represented by an XdmValue whose length
/// happens to be zero. Applications should therefore not test to see whether an object
/// is an instance of this class in order to decide whether it is empty.
/// In interfaces that expect an XdmItem , an empty sequence is represented
/// by a CLI null value.
///
[Serializable]
public sealed class XdmEmptySequence : XdmValue
{
///The singular instance of this class
public static XdmEmptySequence INSTANCE = new XdmEmptySequence();
private XdmEmptySequence()
{
this.value = JEmptySequence.getInstance();
}
}
///
/// The QName class represents an instance of xs:QName, as defined in the XPath 2.0
/// data model. Internally, it has three components, a namespace URI, a local name, and
/// a prefix. The prefix is intended to be used only when converting the value back to
/// a string.
///
///
/// Note that a QName is not itself an XdmItem in this model; however it can
/// be wrapped in an XdmItem.
///
[Serializable]
public sealed class QName
{
private String prefix;
private String uri;
private String local;
int hashcode = -1; // evaluated lazily
int fingerprint = -1; // evaluated only if the QName is registered with the Processor
private NamePool pool = null;
private static String XS = NamespaceConstant.SCHEMA;
/// QName constant for the name xs:string
public static readonly QName XS_STRING = new QName(XS, "xs:string");
/// QName constant for the name xs:integer
public static readonly QName XS_INTEGER = new QName(XS, "xs:integer");
/// QName constant for the name xs:double
public static readonly QName XS_DOUBLE = new QName(XS, "xs:double");
/// QName constant for the name xs:float
public static readonly QName XS_FLOAT = new QName(XS, "xs:float");
/// QName constant for the name xs:decimal
public static readonly QName XS_DECIMAL = new QName(XS, "xs:decimal");
/// QName constant for the name xs:boolean
public static readonly QName XS_BOOLEAN = new QName(XS, "xs:boolean");
/// QName constant for the name xs:anyURI
public static readonly QName XS_ANYURI = new QName(XS, "xs:anyURI");
/// QName constant for the name xs:QName
public static readonly QName XS_QNAME = new QName(XS, "xs:QName");
/// QName constant for the name xs:untypedAtomic
public static readonly QName XS_UNTYPED_ATOMIC = new QName(XS, "xdt:untypedAtomic");
/// QName constant for the name xs:untypedAtomic (for backwards compatibility)
public static readonly QName XDT_UNTYPED_ATOMIC = new QName(XS, "xdt:untypedAtomic");
///
/// Construct a QName using a namespace URI and a lexical representation.
/// The lexical representation may be a local name on its own, or it may
/// be in the form prefix:local-name
///
///
/// This constructor does not check that the components of the QName are
/// lexically valid.
///
/// The namespace URI. Use either the string "" or null
/// for names that are not in any namespace.
///
/// Either the local part of the name, or the prefix
/// and local part in the format prefix:local
///
public QName(String uri, String lexical)
{
// TODO: check for validity
this.uri = (uri == null ? "" : uri);
int colon = lexical.IndexOf(':');
if (colon < 0)
{
this.prefix = "";
this.local = lexical;
}
else
{
this.prefix = lexical.Substring(0, colon);
this.local = lexical.Substring(colon + 1);
}
}
///
/// Construct a QName using a namespace prefix, a namespace URI, and a local name
/// (in that order).
///
///
/// This constructor does not check that the components of the QName are
/// lexically valid.
///
/// The prefix of the name. Use either the string ""
/// or null for names that have no prefix (that is, they are in the default
/// namespace)
/// The namespace URI. Use either the string "" or null
/// for names that are not in any namespace.
///
/// The local part of the name
public QName(String prefix, String uri, String local)
{
this.uri = (uri == null ? String.Empty : uri);
this.local = local;
this.prefix = (prefix == null ? String.Empty : prefix);
}
///
/// Construct a QName from a lexical QName, supplying an element node whose
/// in-scope namespaces are to be used to resolve any prefix contained in the QName.
///
///
/// This constructor checks that the components of the QName are
/// lexically valid.
/// If the lexical QName has no prefix, the name is considered to be in the
/// default namespace, as defined by xmlns="..." .
/// If the prefix of the lexical QName is not in scope, returns null.
///
/// The lexical QName, in the form prefix:local
/// or simply local .
/// The element node whose in-scope namespaces are to be used
/// to resolve the prefix part of the lexical QName.
/// If the prefix of the lexical QName is not in scope
/// If the lexical QName is invalid
/// (for example, if it contains invalid characters)
///
public QName(String lexicalQName, XdmNode element)
{
try
{
NodeInfo node = (NodeInfo)element.value;
NamePool pool = node.getConfiguration().getNamePool();
int nc = pool.allocateLexicalQName(lexicalQName, true, new InscopeNamespaceResolver(node),
node.getConfiguration().getNameChecker());
this.uri = pool.getURI(nc);
this.local = pool.getLocalName(nc);
this.prefix = pool.getPrefix(nc);
}
catch (net.sf.saxon.trans.XPathException err)
{
throw new ArgumentException(err.getMessage());
}
}
///
/// Construct a QName from an XmlQualifiedName (as defined in the
/// System.Xml package).
///
///
/// Note that an XmlQualifiedName does not contain any prefix, so the result
/// will always have a prefix of ""
///
/// The XmlQualifiedName
public QName(XmlQualifiedName qualifiedName)
{
this.uri = qualifiedName.Namespace;
this.local = qualifiedName.Name;
this.prefix = String.Empty;
}
// internal constructor from a QNameValue
internal QName(QNameValue q)
{
this.uri = q.getNamespaceURI();
this.prefix = q.getPrefix();
this.local = q.getLocalName();
}
///
/// Factory method to construct a QName from a string containing the expanded
/// QName in Clark notation, that is, {uri}local
///
///
/// The prefix part of the QName will be set to an empty string.
///
/// The URI in Clark notation: {uri}local if the
/// name is in a namespace, or simply local if not.
public static QName FromClarkName(String expandedName)
{
String namespaceURI;
String localName;
if (expandedName[0] == '{')
{
int closeBrace = expandedName.IndexOf('}');
if (closeBrace < 0)
{
throw new ArgumentException("No closing '}' in Clark name");
}
namespaceURI = expandedName.Substring(1, closeBrace - 1);
if (closeBrace == expandedName.Length)
{
throw new ArgumentException("Missing local part in Clark name");
}
localName = expandedName.Substring(closeBrace + 1);
}
else
{
namespaceURI = "";
localName = expandedName;
}
return new QName("", namespaceURI, localName);
}
///
/// Register a QName with the Processor . This makes comparison faster
/// when the QName is compared with others that are also registered with the Processor .
///
/// The Processor in which the name is to be registered.
public void Register(Processor processor)
{
pool = processor.config.getNamePool();
fingerprint = pool.allocate(prefix, uri, local) & 0xfffff;
}
///
/// Validate the QName against the XML 1.0 or XML 1.1 rules for valid names.
///
/// The Processor in which the name is to be validated.
/// This determines whether the XML 1.0 or XML 1.1 rules for forming names are used.
/// true if the name is valid, false if not
public bool IsValid(Processor processor)
{
NameChecker nc = processor.config.getNameChecker();
if (prefix != String.Empty)
{
if (!nc.isValidNCName(prefix))
{
return false;
}
}
if (!nc.isValidNCName(local))
{
return false;
}
return true;
}
/// The prefix of the QName. This plays no role in operations such as comparison
/// of QNames for equality, but is retained (as specified in XPath) so that a string representation
/// can be reconstructed.
///
///
/// Returns the zero-length string in the case of a QName that has no prefix.
///
public String Prefix
{
get { return prefix; }
}
/// The namespace URI of the QName. Returns "" (the zero-length string) if the
/// QName is not in a namespace.
///
public String Uri
{
get { return uri; }
}
/// The local part of the QName
public String LocalName
{
get { return local; }
}
/// The expanded name, as a string using the notation devised by James Clark.
/// If the name is in a namespace, the resulting string takes the form {uri}local .
/// Otherwise, the value is the local part of the name.
///
public String ClarkName
{
get
{
if (uri == "")
{
return local;
}
else
{
return "{" + uri + "}" + local;
}
}
}
///
/// Convert the value to a string. The resulting string is the lexical form of the QName,
/// using the original prefix if there was one.
///
public override String ToString()
{
if (prefix == "")
{
return local;
}
else
{
return prefix + ":" + uri;
}
}
///
/// Get a hash code for the QName, to support equality matching. This supports the
/// semantics of equality, which considers only the namespace URI and local name, and
/// not the prefix.
///
///
/// The algorithm for allocating a hash code does not depend on registering the QName
/// with the Processor .
///
public override int GetHashCode()
{
if (hashcode == -1)
{
hashcode = ClarkName.GetHashCode();
}
return hashcode;
}
///
/// Test whether two QNames are equal. This supports the
/// semantics of equality, which considers only the namespace URI and local name, and
/// not the prefix.
///
///
/// The result of the function does not depend on registering the QName
/// with the Processor , but is computed more quickly if the QNames have
/// both been registered
///
/// The value to be compared with this QName. If this value is not a QName, the
/// result is always false. Otherwise, it is true if the namespace URI and local name both match.
public override bool Equals(Object other)
{
if (!(other is QName))
{
return false;
}
if (pool != null && pool == ((QName)other).pool)
{
return fingerprint == ((QName)other).fingerprint;
}
if (GetHashCode() != ((QName)other).GetHashCode())
{
return false;
}
return ClarkName == ((QName)other).ClarkName;
//TODO: avoid computing ClarkName more than once
}
///
/// Convert the value to an XmlQualifiedName (as defined in the
/// System.Xml package)
///
///
/// Note that this loses the prefix.
///
public XmlQualifiedName ToXmlQualifiedName()
{
return new XmlQualifiedName(local, uri);
}
///
/// Convert to a net.sf.saxon.value.QNameValue
///
internal QNameValue ToQNameValue()
{
return new QNameValue(prefix, uri, local, null);
}
}
///
/// This class represents an enumeration of the values in an XPath
/// sequence. It implements the IEnumerator interface, and the objects
/// returned are always instances of XPathItem
///
///
/// Because the underlying value can be evaluated lazily, it is possible
/// for exceptions to occur as the sequence is being read.
///
[Serializable]
public class SequenceEnumerator : IEnumerator
{
private SequenceIterator iter;
internal SequenceEnumerator(SequenceIterator iter)
{
this.iter = iter;
}
/// Return the current item in the sequence
/// An object which will always be an instance of XdmItem
public object Current
{
get { return XdmValue.Wrap(iter.current()); }
}
/// Move to the next item in the sequence
/// true if there are more items in the sequence
public bool MoveNext()
{
return (iter.next() != null);
}
/// Reset the enumeration so that the next call of
/// MoveNext will position the enumeration at the
/// first item in the sequence
public void Reset()
{
iter = iter.getAnother();
}
}
///
/// Enumeration identifying the thirteen XPath axes
///
public enum XdmAxis
{
/// The XPath ancestor axis
Ancestor,
/// The XPath ancestor-or-self axis
AncestorOrSelf,
/// The XPath attribute axis
Attribute,
/// The XPath child axis
Child,
/// The XPath descendant axis
Descendant,
/// The XPath descandant-or-self axis
DescendantOrSelf,
/// The XPath following axis
Following,
/// The XPath following-sibling axis
FollowingSibling,
/// The XPath namespace axis
Namespace,
/// The XPath parent axis
Parent,
/// The XPath preceding axis
Preceding,
/// The XPath preceding-sibling axis
PrecedingSibling,
/// The XPath self axis
Self
}
internal class EmptyEnumerator : IEnumerator
{
public static EmptyEnumerator INSTANCE = new EmptyEnumerator();
private EmptyEnumerator() { }
public void Reset() { }
public object Current
{
get { throw new InvalidOperationException("Collection is empty."); }
}
public bool MoveNext()
{
return false;
}
}
}
//
// 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.
//