X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.XML%2FSystem.Xml.XPath%2FXPathNavigator.cs;h=2e72e136cc8741bf7531393198cb79db539c2a36;hb=03a0f59d34d314ffe49359e849b7431d453cbe78;hp=0a017a2ffbfc017ae1b15d97ef5c85a0e1d3807c;hpb=2e5903d155bcce8261673d10b71394ae107ffadc;p=mono.git diff --git a/mcs/class/System.XML/System.Xml.XPath/XPathNavigator.cs b/mcs/class/System.XML/System.Xml.XPath/XPathNavigator.cs index 0a017a2ffbf..2e72e136cc8 100644 --- a/mcs/class/System.XML/System.Xml.XPath/XPathNavigator.cs +++ b/mcs/class/System.XML/System.Xml.XPath/XPathNavigator.cs @@ -3,16 +3,57 @@ // // Author: // Jason Diamond (jason@injektilo.org) +// Atsushi Enomoto (atsushi@ximian.com) // // (C) 2002 Jason Diamond http://injektilo.org/ +// (C) 2004 Novell Inc. +// + +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; +using System.Collections; +using System.IO; +using System.Xml; +using System.Xml.Schema; using Mono.Xml.XPath; +#if NET_2_0 +using MS.Internal.Xml; +#endif + +#if NET_2_0 +using NSResolver = System.Xml.IXmlNamespaceResolver; +#else +using NSResolver = System.Xml.XmlNamespaceManager; +#endif namespace System.Xml.XPath { +#if NET_2_0 + public abstract class XPathNavigator : XPathItem, + ICloneable, IXPathNavigable, IXmlNamespaceResolver +#else public abstract class XPathNavigator : ICloneable +#endif { #region Constructor @@ -26,9 +67,19 @@ namespace System.Xml.XPath public abstract string BaseURI { get; } +#if NET_2_0 + public virtual bool HasAttributes { + get { return Clone ().MoveToFirstAttribute (); } + } + + public virtual bool HasChildren { + get { return Clone ().MoveToFirstChild (); } + } +#else public abstract bool HasAttributes { get; } public abstract bool HasChildren { get; } +#endif public abstract bool IsEmptyElement { get; } @@ -44,9 +95,40 @@ namespace System.Xml.XPath public abstract string Prefix { get; } +#if NET_2_0 + public virtual string XmlLang { + get { + XPathNavigator nav = Clone (); + switch (nav.NodeType) { + case XPathNodeType.Attribute: + case XPathNodeType.Namespace: + nav.MoveToParent (); + break; + } + do { + if (nav.MoveToAttribute ("lang", "http://www.w3.org/XML/1998/namespace")) + return nav.Value; + } while (nav.MoveToParent ()); + return String.Empty; + } + } +#else public abstract string Value { get; } public abstract string XmlLang { get; } +#endif + + int Depth + { + get + { + int cLevels = 0; + XPathNavigator nav = Clone (); + while (nav.MoveToParent ()) + cLevels ++; + return cLevels; + } + } #endregion @@ -54,19 +136,100 @@ namespace System.Xml.XPath public abstract XPathNavigator Clone (); - [MonoTODO] public virtual XmlNodeOrder ComparePosition (XPathNavigator nav) { - throw new NotImplementedException (); + if (IsSamePosition (nav)) + return XmlNodeOrder.Same; + + XPathNavigator nav1 = Clone (); + XPathNavigator nav2 = nav.Clone (); + + int nDepth1 = nav1.Depth; + int nDepth2 = nav2.Depth; + + if (nDepth1 > nDepth2) + { + while (nDepth1 > nDepth2) + { + if (!nav1.MoveToParent ()) + break; + nDepth1 --; + } + if (nav1.IsSamePosition (nav2)) + return XmlNodeOrder.After; + } + else if (nDepth1 < nDepth2) + { + while (nDepth1 < nDepth2) + { + if (!nav2.MoveToParent ()) + break; + nDepth2 --; + } + if (nav1.IsSamePosition (nav2)) + return XmlNodeOrder.Before; + } + + XPathNavigator parent1 = nav1.Clone (); + XPathNavigator parent2 = nav2.Clone (); + while (parent1.MoveToParent () && parent2.MoveToParent ()) + { + if (parent1.IsSamePosition (parent2)) + { + // the ordering is namespace, attribute, children + // assume that nav1 is before nav2, find counter-example + if (nav1.NodeType == XPathNodeType.Namespace) + { + if (nav2.NodeType == XPathNodeType.Namespace) + { + // match namespaces + while (nav2.MoveToNextNamespace ()) + if (nav2.IsSamePosition (nav1)) + return XmlNodeOrder.After; + } + } + else if (nav1.NodeType == XPathNodeType.Attribute) + { + if (nav2.NodeType == XPathNodeType.Namespace) + return XmlNodeOrder.After; + else if (nav2.NodeType == XPathNodeType.Attribute) + { + // match attributes + while (nav2.MoveToNextAttribute ()) + if (nav2.IsSamePosition (nav1)) + return XmlNodeOrder.After; + } + } + else + { + switch (nav2.NodeType) { + case XPathNodeType.Namespace: + case XPathNodeType.Attribute: + return XmlNodeOrder.After; + } + // match children + while (nav2.MoveToNext ()) + if (nav2.IsSamePosition (nav1)) + return XmlNodeOrder.After; + } + return XmlNodeOrder.Before; + } + nav1.MoveToParent (); + nav2.MoveToParent (); + } + return XmlNodeOrder.Unknown; } public virtual XPathExpression Compile (string xpath) { - Tokenizer tokenizer = new Tokenizer (xpath); XPathParser parser = new XPathParser (); - Expression expr = (Expression) parser.yyparseSafe (tokenizer); -// Expression expr = (Expression) parser.yyparseDebug (tokenizer); - return new CompiledExpression (expr); + return new CompiledExpression (parser.Compile (xpath)); + } + + internal virtual XPathExpression Compile (string xpath, System.Xml.Xsl.IStaticXsltContext ctx) + { + XPathParser parser = new XPathParser (ctx); + return new CompiledExpression (parser.Compile (xpath)); } public virtual object Evaluate (string xpath) @@ -80,16 +243,99 @@ namespace System.Xml.XPath } public virtual object Evaluate (XPathExpression expr, XPathNodeIterator context) + { + return Evaluate (expr, context, null); + } + + internal virtual object Evaluate (XPathExpression expr, XPathNodeIterator context, NSResolver ctx) + { + CompiledExpression cexpr = (CompiledExpression) expr; + if (ctx == null) + ctx = cexpr.NamespaceManager; + + if (context == null) + context = new NullIterator (this, ctx); + BaseIterator iterContext = (BaseIterator) context; + iterContext.NamespaceManager = ctx; + return cexpr.Evaluate (iterContext); + } + + internal XPathNodeIterator EvaluateNodeSet (XPathExpression expr, XPathNodeIterator context, NSResolver ctx) + { + CompiledExpression cexpr = (CompiledExpression) expr; + if (ctx == null) + ctx = cexpr.NamespaceManager; + + if (context == null) + context = new NullIterator (this, cexpr.NamespaceManager); + BaseIterator iterContext = (BaseIterator) context; + iterContext.NamespaceManager = ctx; + return cexpr.EvaluateNodeSet (iterContext); + } + + internal string EvaluateString (XPathExpression expr, XPathNodeIterator context, NSResolver ctx) + { + CompiledExpression cexpr = (CompiledExpression) expr; + if (ctx == null) + ctx = cexpr.NamespaceManager; + + if (context == null) + context = new NullIterator (this, cexpr.NamespaceManager); + BaseIterator iterContext = (BaseIterator) context; + iterContext.NamespaceManager = ctx; + return cexpr.EvaluateString (iterContext); + } + + internal double EvaluateNumber (XPathExpression expr, XPathNodeIterator context, NSResolver ctx) { CompiledExpression cexpr = (CompiledExpression) expr; + if (ctx == null) + ctx = cexpr.NamespaceManager; + if (context == null) context = new NullIterator (this, cexpr.NamespaceManager); - return cexpr.Evaluate ((BaseIterator) context); + BaseIterator iterContext = (BaseIterator) context; + iterContext.NamespaceManager = ctx; + return cexpr.EvaluateNumber (iterContext); + } + + internal bool EvaluateBoolean (XPathExpression expr, XPathNodeIterator context, NSResolver ctx) + { + CompiledExpression cexpr = (CompiledExpression) expr; + if (ctx == null) + ctx = cexpr.NamespaceManager; + + if (context == null) + context = new NullIterator (this, cexpr.NamespaceManager); + BaseIterator iterContext = (BaseIterator) context; + iterContext.NamespaceManager = ctx; + return cexpr.EvaluateBoolean (iterContext); + } + +#if NET_2_0 + public virtual string GetAttribute (string localName, string namespaceURI) + { + XPathNavigator nav = Clone (); + if (nav.MoveToAttribute (localName, namespaceURI)) + return nav.Value; + else + return String.Empty; + } + + public virtual string GetNamespace (string name) + { + XPathNavigator nav = Clone (); + if (nav.MoveToNamespace (name)) + return nav.Value; + else + return String.Empty; } +#else public abstract string GetAttribute (string localName, string namespaceURI); public abstract string GetNamespace (string name); +#endif object ICloneable.Clone () { @@ -119,13 +365,56 @@ namespace System.Xml.XPath public virtual bool Matches (XPathExpression expr) { - XPathNodeIterator nodes = Select (expr); + Expression e = ((CompiledExpression) expr).ExpressionNode; + if (e is ExprRoot) + return NodeType == XPathNodeType.Root; + + NodeTest nt = e as NodeTest; + if (nt != null) { + switch (nt.Axis.Axis) { + case Axes.Child: + case Axes.Attribute: + break; + default: + throw new XPathException ("Only child and attribute pattern are allowed for a pattern."); + } + return nt.Match (((CompiledExpression)expr).NamespaceManager, this); + } + if (e is ExprFilter) { + do { + e = ((ExprFilter) e).LeftHandSide; + } while (e is ExprFilter); + + if (e is NodeTest && !((NodeTest) e).Match (((CompiledExpression) expr).NamespaceManager, this)) + return false; + } + + XPathResultType resultType = e.ReturnType; + switch (resultType) { + case XPathResultType.Any: + case XPathResultType.NodeSet: + break; + default: + return false; + } + switch (e.EvaluatedNodeType) { + case XPathNodeType.Attribute: + case XPathNodeType.Namespace: + if (NodeType != e.EvaluatedNodeType) + return false; + break; + } + + XPathNodeIterator nodes; + nodes = this.Select (expr); while (nodes.MoveNext ()) { if (IsSamePosition (nodes.Current)) return true; } + // ancestors might select this node. + XPathNavigator navigator = Clone (); while (navigator.MoveToParent ()) { @@ -142,10 +431,57 @@ namespace System.Xml.XPath public abstract bool MoveTo (XPathNavigator other); +#if NET_2_0 + public virtual bool MoveToAttribute (string localName, string namespaceURI) + { + if (MoveToFirstAttribute ()) { + do { + if (LocalName == localName && NamespaceURI == namespaceURI) + return true; + } while (MoveToNextAttribute ()); + MoveToParent (); + } + return false; + } + + public virtual bool MoveToNamespace (string name) + { + if (MoveToFirstNamespace ()) { + do { + if (LocalName == name) + return true; + } while (MoveToNextNamespace ()); + MoveToParent (); + } + return false; + } + + public virtual bool MoveToFirst () + { + if (MoveToPrevious ()) { + // It would be able to invoke MoveToPrevious() until the end, but this way would be much faster + MoveToParent (); + MoveToFirstChild (); + return true; + } + return false; + } + + public virtual void MoveToRoot () + { + while (MoveToParent ()) + ; + } +#else public abstract bool MoveToAttribute (string localName, string namespaceURI); + public abstract bool MoveToNamespace (string name); + public abstract bool MoveToFirst (); + public abstract void MoveToRoot (); +#endif + public abstract bool MoveToFirstAttribute (); public abstract bool MoveToFirstChild (); @@ -159,8 +495,6 @@ namespace System.Xml.XPath public abstract bool MoveToId (string id); - public abstract bool MoveToNamespace (string name); - public abstract bool MoveToNext (); public abstract bool MoveToNextAttribute (); @@ -176,81 +510,83 @@ namespace System.Xml.XPath public abstract bool MoveToPrevious (); - public abstract void MoveToRoot (); - public virtual XPathNodeIterator Select (string xpath) { return Select (Compile (xpath)); } public virtual XPathNodeIterator Select (XPathExpression expr) + { + return Select (expr, null); + } + + internal virtual XPathNodeIterator Select (XPathExpression expr, NSResolver ctx) { CompiledExpression cexpr = (CompiledExpression) expr; - BaseIterator iter = new NullIterator (this, cexpr.NamespaceManager); + if (ctx == null) + ctx = cexpr.NamespaceManager; + + BaseIterator iter = new NullIterator (this, ctx); return cexpr.EvaluateNodeSet (iter); } public virtual XPathNodeIterator SelectAncestors (XPathNodeType type, bool matchSelf) { Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor; - NodeTest test = new NodeTypeTest (axis, type); - return SelectTest (test); + return SelectTest (new NodeTypeTest (axis, type)); } - [MonoTODO] public virtual XPathNodeIterator SelectAncestors (string name, string namespaceURI, bool matchSelf) { - if (namespaceURI != null && namespaceURI != "") - throw new NotImplementedException (); + if (name == null) + throw new ArgumentNullException ("name"); + if (namespaceURI == null) + throw new ArgumentNullException ("namespaceURI"); Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor; - XmlQualifiedName qname = new XmlQualifiedName (name); - NodeTest test = new NodeNameTest (axis, qname); - return SelectTest (test); + XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI); + return SelectTest (new NodeNameTest (axis, qname, true)); } public virtual XPathNodeIterator SelectChildren (XPathNodeType type) { - NodeTest test = new NodeTypeTest (Axes.Child, type); - return SelectTest (test); + return SelectTest (new NodeTypeTest (Axes.Child, type)); } - [MonoTODO] public virtual XPathNodeIterator SelectChildren (string name, string namespaceURI) { - if (namespaceURI != null && namespaceURI != "") - throw new NotImplementedException (); + if (name == null) + throw new ArgumentNullException ("name"); + if (namespaceURI == null) + throw new ArgumentNullException ("namespaceURI"); Axes axis = Axes.Child; - XmlQualifiedName qname = new XmlQualifiedName (name); - NodeTest test = new NodeNameTest (axis, qname); - return SelectTest (test); + XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI); + return SelectTest (new NodeNameTest (axis, qname, true)); } public virtual XPathNodeIterator SelectDescendants (XPathNodeType type, bool matchSelf) { Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant; - NodeTest test = new NodeTypeTest (axis, type); - return SelectTest (test); + return SelectTest (new NodeTypeTest (axis, type)); } - [MonoTODO] public virtual XPathNodeIterator SelectDescendants (string name, string namespaceURI, bool matchSelf) { - if (namespaceURI != null && namespaceURI != "") - throw new NotImplementedException (); + if (name == null) + throw new ArgumentNullException ("name"); + if (namespaceURI == null) + throw new ArgumentNullException ("namespaceURI"); + Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant; - XmlQualifiedName qname = new XmlQualifiedName (name); - NodeTest test = new NodeNameTest (axis, qname); - return SelectTest (test); + XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI); + return SelectTest (new NodeNameTest (axis, qname, true)); } internal XPathNodeIterator SelectTest (NodeTest test) { - Expression expr = new ExprStep (test, null); - BaseIterator iter = new NullIterator (this, null); - return expr.EvaluateNodeSet (iter); + return test.EvaluateNodeSet (new NullIterator (this)); } public override string ToString () @@ -259,5 +595,284 @@ namespace System.Xml.XPath } #endregion + +#if NET_2_0 + + [MonoTODO] + public virtual bool CheckValidity (XmlSchemaSet schemas, ValidationEventHandler handler) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual object CopyAsObject (Type targetType) + { + throw new NotImplementedException (); + } + + public virtual XPathNavigator CreateNavigator () + { + return Clone (); + } + + [MonoTODO] + public virtual object Evaluate (string xpath, IXmlNamespaceResolver nsResolver) + { + return Evaluate (Compile (xpath), null, nsResolver); + } + + [MonoTODO] + public virtual IDictionary GetNamespacesInScope (XmlNamespaceScope scope) + { + throw new NotImplementedException (); + } + + public virtual string LookupNamespace (string prefix) + { + return LookupNamespace (prefix, false); + } + + public virtual string LookupNamespace (string prefix, bool atomizedNames) + { + XPathNavigator nav = Clone (); + if (nav.NodeType != XPathNodeType.Element) + nav.MoveToParent (); + if (nav.MoveToNamespace (prefix)) { + if (atomizedNames) + return nav.NameTable.Add (nav.Value); + else + return nav.Value; + } + return null; + } + + public virtual string LookupPrefix (string namespaceUri) + { + return LookupPrefix (namespaceUri, false); + } + + [MonoTODO] + public virtual string LookupPrefix (string namespaceUri, bool atomizedNames) + { + throw new NotImplementedException (); + } + + public virtual bool MoveToAttribute (string localName, string namespaceURI, bool atomizedNames) + { + return MoveToAttribute (localName, namespaceURI); + } + + private bool MoveTo (XPathNodeIterator iter) + { + if (iter.MoveNext ()) { + MoveTo (iter.Current); + return true; + } + else + return false; + } + + public virtual bool MoveToChild (XPathNodeType type) + { + return MoveTo (SelectChildren (type)); + } + + public virtual bool MoveToChild (string localName, string namespaceURI) + { + return MoveTo (SelectChildren (localName, namespaceURI)); + } + + public virtual bool MoveToChild (string localName, string namespaceURI, bool atomizedNames) + { + return MoveToChild (localName, namespaceURI); + } + + public virtual bool MoveToDescendant (XPathNodeType type) + { + return MoveTo (SelectDescendants (type, false)); + } + + public virtual bool MoveToDescendant (string localName, string namespaceURI) + { + return MoveTo (SelectDescendants (localName, namespaceURI, false)); + } + + public virtual bool MoveToDescendant (string localName, string namespaceURI, bool atomizedNames) + { + return MoveToDescendant (localName, namespaceURI); + } + + public virtual bool MoveToNext (string localName, string namespaceURI) + { + XPathNavigator nav = Clone (); + while (nav.MoveToNext ()) { + if (nav.LocalName == localName && + nav.NamespaceURI == namespaceURI) { + MoveTo (nav); + return true; + } + } + return false; + } + + public virtual bool MoveToNext (string localName, string namespaceURI, bool atomizedNames) + { + return MoveToNext (localName, namespaceURI); + } + + public virtual bool MoveToNext (XPathNodeType type) + { + XPathNavigator nav = Clone (); + while (nav.MoveToNext ()) { + if (nav.NodeType == type) { + MoveTo (nav); + return true; + } + } + return false; + } + + [MonoTODO] + public virtual XmlReader ReadSubtree () + { + throw new NotImplementedException (); + } + + public virtual XPathNodeIterator Select (string xpath, IXmlNamespaceResolver nsResolver) + { + return Select (Compile (xpath), nsResolver); + } + + public virtual XPathNavigator SelectSingleNode (string xpath) + { + return SelectSingleNode (xpath, null); + } + + public virtual XPathNavigator SelectSingleNode (string xpath, IXmlNamespaceResolver nsResolver) + { + XPathExpression expr = Compile (xpath); + expr.SetContext (nsResolver); + return SelectSingleNode (expr); + } + + public XPathNavigator SelectSingleNode (XPathExpression expression) + { + XPathNodeIterator iter = Select (expression); + if (iter.MoveNext ()) + return iter.Current; + else + return null; + } + + [MonoTODO] + public override object ValueAs (Type type, IXmlNamespaceResolver nsResolver) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public virtual void WriteSubtree (XmlWriter writer) + { + XmlReader st = ReadSubtree (); + writer.WriteNode (st, false); + } + + [MonoTODO] + public virtual string InnerXml { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public override bool IsNode { + get { return true; } + } + + [MonoTODO] + public virtual IKeyComparer NavigatorComparer { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public virtual string OuterXml { + get { + StringWriter sw = new StringWriter (); + XmlTextWriter xtw = new XmlTextWriter (sw); + WriteSubtree (xtw); + xtw.Close (); + return sw.ToString (); + } + } + + [MonoTODO] + public virtual IXmlSchemaInfo SchemaInfo { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public override object TypedValue { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public virtual object UnderlyingObject { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public override bool ValueAsBoolean { + get { return XQueryConvert.StringToBoolean (Value); } + } + + [MonoTODO] + public override DateTime ValueAsDateTime { + get { return XmlConvert.ToDateTime (Value); } + } + + [MonoTODO] + public override decimal ValueAsDecimal { + get { return XQueryConvert.StringToDecimal (Value); } + } + + [MonoTODO] + public override double ValueAsDouble { + get { return XQueryConvert.StringToDouble (Value); } + } + + [MonoTODO] + public override int ValueAsInt32 { + get { return XQueryConvert.StringToInt (Value); } + } + + [MonoTODO] + public override long ValueAsInt64 { + get { return XQueryConvert.StringToInteger (Value); } + } + + [MonoTODO] + public override ICollection ValueAsList { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public override float ValueAsSingle { + get { return XQueryConvert.StringToFloat (Value); } + } + + [MonoTODO] + public override Type ValueType { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public override XmlSchemaType XmlType { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + protected XmlReader GetValidatingReader (XmlSchemaSet schemas, ValidationEventHandler handler, XmlSchemaType schemaType) + { + throw new NotImplementedException (); + } +#endif } }