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

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

Go to download

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

The newest version!
using System;
using System.IO;
using System.Xml;
using System.Collections;
using 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.
//




© 2015 - 2024 Weber Informatics LLC | Privacy Policy