// (C) 2003 Atsushi Enomoto
//
+//
+// 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.Xml;
+using System.Xml.Schema;
using System.Xml.XPath;
namespace System.Xml
private XmlDocument document;
// Current namespace node (ancestor's attribute of current node).
private XmlAttribute nsNode;
- private ArrayList iteratedNsNames = new ArrayList ();
+ private ArrayList iteratedNsNames;
#endregion
#region Properties
if (NsNode != null)
return false;
- if (node.Attributes != null)
- for (int i = 0; i < node.Attributes.Count; i++)
- if (node.Attributes [i].NamespaceURI != Xmlns)
- return true;
+ XmlElement el = node as XmlElement;
+ if (el == null || !el.HasAttributes)
+ return false;
+
+ for (int i = 0; i < node.Attributes.Count; i++)
+ if (node.Attributes [i].NamespaceURI != Xmlns)
+ return true;
return false;
}
}
XPathNodeType nodeType = NodeType;
bool canHaveChildren = nodeType == XPathNodeType.Root || nodeType == XPathNodeType.Element;
- return canHaveChildren && node.FirstChild != null;
+ return canHaveChildren && GetFirstChild (node) != null;
}
}
get { return nsNode; }
set {
if (value == null)
- iteratedNsNames.Clear ();
+ iteratedNsNames = null;
else
+ {
+ if (iteratedNsNames == null)
+ iteratedNsNames = new ArrayList();
+ else
+ {
+ if (iteratedNsNames.IsReadOnly)
+ iteratedNsNames = new ArrayList(iteratedNsNames);
+ }
iteratedNsNames.Add (value.Name);
+ }
nsNode = value;
}
}
}
public override XPathNodeType NodeType {
- get { return (NsNode != null) ? XPathNodeType.Namespace : node.XPathNodeType; }
+ get {
+ if (NsNode != null)
+ return XPathNodeType.Namespace;
+ XmlNode n = node;
+ bool sw = false;
+ do {
+ switch (n.NodeType) {
+ case XmlNodeType.SignificantWhitespace:
+ sw = true;
+ n = GetNextSibling (n);
+ break;
+ case XmlNodeType.Whitespace:
+ n = GetNextSibling (n);
+ break;
+ case XmlNodeType.Text:
+ case XmlNodeType.CDATA:
+ return XPathNodeType.Text;
+ default:
+ n = null;
+ break;
+ }
+ } while (n != null);
+ return sw ?
+ XPathNodeType.SignificantWhitespace :
+ node.XPathNodeType;
+ }
}
public override string Prefix {
get { return (NsNode != null) ? String.Empty : node.Prefix; }
}
+#if NET_2_0
+ public override IXmlSchemaInfo SchemaInfo {
+ get { return NsNode != null ? null : node.SchemaInfo; }
+ }
+
+ public override object UnderlyingObject {
+ get { return node; }
+ }
+#endif
+
public override string Value {
get {
switch (NodeType) {
case XPathNodeType.Whitespace:
case XPathNodeType.SignificantWhitespace:
string value = node.Value;
- for (XmlNode n = node.NextSibling; n != null; n = n.NextSibling) {
+ for (XmlNode n = GetNextSibling (node); n != null; n = GetNextSibling (n)) {
switch (n.XPathNodeType) {
case XPathNodeType.Text:
case XPathNodeType.Whitespace:
private bool CheckNsNameAppearance (string name, string ns)
{
- if (iteratedNsNames.Contains (name))
+ if (iteratedNsNames != null && iteratedNsNames.Contains (name))
return true;
// default namespace erasure - just add name and never return this node
if (ns == String.Empty) {
+ if (iteratedNsNames == null)
+ iteratedNsNames = new ArrayList();
+ else
+ {
+ if (iteratedNsNames.IsReadOnly)
+ iteratedNsNames = new ArrayList(iteratedNsNames);
+ }
iteratedNsNames.Add ("xmlns");
return true;
}
{
XmlDocumentNavigator clone = new XmlDocumentNavigator (node, nsNodeXml);
clone.nsNode = nsNode;
- clone.iteratedNsNames = (ArrayList) iteratedNsNames.Clone ();
+ clone.iteratedNsNames = (iteratedNsNames == null || iteratedNsNames.IsReadOnly) ? iteratedNsNames : ArrayList.ReadOnly(iteratedNsNames);
return clone;
}
// returns actual namespace for the other nodes.
return Node.GetNamespaceOfPrefix (name);
}
-
+
+ public override bool IsDescendant (XPathNavigator other)
+ {
+ if (NsNode != null)
+ return false;
+ XmlDocumentNavigator o = other as XmlDocumentNavigator;
+ if (o == null)
+ return false;
+ XmlNode n =
+ o.node.NodeType == XmlNodeType.Attribute ?
+ ((XmlAttribute) o.node).OwnerElement :
+ o.node.ParentNode;
+ for (;n != null; n = n.ParentNode)
+ if (n == node)
+ return true;
+ return false;
+ }
+
public override bool IsSamePosition (XPathNavigator other)
{
XmlDocumentNavigator otherDocumentNavigator = other as XmlDocumentNavigator;
public override bool MoveToAttribute (string localName, string namespaceURI)
{
- if (node.Attributes != null) {
- for (int i = 0; i < node.Attributes.Count; i++) {
- XmlAttribute attr = node.Attributes [i];
- if (attr.LocalName == localName
- && attr.NamespaceURI == namespaceURI) {
- node = attr;
- NsNode = null;
- return true;
- }
+ if (HasAttributes) {
+ XmlAttribute attr = node.Attributes [localName, namespaceURI];
+ if (attr != null) {
+ node = attr;
+ NsNode = null;
+ return true;
}
}
return false;
}
+#if NET_2_0
+#else
public override bool MoveToFirst ()
{
- if (NsNode == null && node.NodeType != XmlNodeType.Attribute && node.ParentNode != null) {
- if (!MoveToParent ())
- return false;
- // Follow these 2 steps so that we can skip
- // some types of nodes .
- MoveToFirstChild ();
- return true;
- }
- return false;
+ return MoveToFirstImpl ();
}
+#endif
public override bool MoveToFirstAttribute ()
{
- if (node.Attributes == null)
- return false;
if (NodeType == XPathNodeType.Element) {
+ XmlElement el = node as XmlElement;
+ if (!el.HasAttributes)
+ return false;
for (int i = 0; i < node.Attributes.Count; i++) {
XmlAttribute attr = node.Attributes [i];
if (attr.NamespaceURI != Xmlns) {
public override bool MoveToFirstChild ()
{
if (HasChildren) {
- if (node == document) {
- XmlNode n = node.FirstChild;
- if (n == null)
- return false;
- bool loop = true;
- do {
- switch (n.NodeType) {
- case XmlNodeType.XmlDeclaration:
- case XmlNodeType.DocumentType:
- n = n.NextSibling;
- if (n == null)
- return false;
- break;
- default:
- loop = false;
- break;
- }
- } while (loop);
- node = n;
- } else {
- XmlNode n2 = null;
- do {
- n2 = node.FirstChild;
- if (node.NodeType != XmlNodeType.EntityReference)
- break;
- n2 = node.NextSibling;
- } while (n2 != null);
- if (n2 == null)
- return false;
- node = n2;
- }
+ XmlNode n = GetFirstChild (node);
+ if (n == null)
+ return false;
+ node = n;
return true;
}
return false;
if (NodeType != XPathNodeType.Element)
return false;
XmlElement el = node as XmlElement;
- if (node.Attributes != null) {
- do {
+ do {
+ if (el.HasAttributes) {
for (int i = 0; i < el.Attributes.Count; i++) {
XmlAttribute attr = el.Attributes [i];
if (attr.NamespaceURI == Xmlns) {
return true;
}
}
- if (namespaceScope == XPathNamespaceScope.Local)
- return false;
- el = el.ParentNode as XmlElement;
- } while (el != null);
- }
+ }
+ if (namespaceScope == XPathNamespaceScope.Local)
+ return false;
+ el = GetParentNode (el) as XmlElement;
+ } while (el != null);
if (namespaceScope == XPathNamespaceScope.All) {
if (CheckNsNameAppearance (nsNodeXml.Name, nsNodeXml.Value))
return false;
XmlElement el = node as XmlElement;
- if (node.Attributes != null) {
- do {
+ do {
+ if (el.HasAttributes) {
for (int i = 0; i < el.Attributes.Count; i++) {
XmlAttribute attr = el.Attributes [i];
if (attr.NamespaceURI == Xmlns && attr.Name == name) {
return true;
}
}
- el = node.ParentNode as XmlElement;
- } while (el != null);
- }
+ }
+ el = GetParentNode (node) as XmlElement;
+ } while (el != null);
return false;
}
XmlNode n = node;
if (NodeType == XPathNodeType.Text) {
do {
- n = n.NextSibling;
+ n = GetNextSibling (n);
if (n == null)
return false;
switch (n.NodeType) {
case XmlNodeType.CDATA:
- case XmlNodeType.EntityReference:
case XmlNodeType.SignificantWhitespace:
case XmlNodeType.Text:
case XmlNodeType.Whitespace:
}
break;
} while (true);
- } else {
- n = n.NextSibling;
- if (n == null)
- return false;
- }
-
- if (n.ParentNode != null && n.ParentNode.NodeType == XmlNodeType.Document) {
- while (n != null) {
- switch (n.NodeType) {
- case XmlNodeType.DocumentType:
- case XmlNodeType.XmlDeclaration:
- n = n.NextSibling;
- continue;
- }
- break;
- }
- if (n != null)
- node = n;
- else
- return false;
- } else {
- while (n != null) {
- if (n.NodeType != XmlNodeType.EntityReference)
- break;
- n = n.NextSibling;
- }
- if (n != null)
- node = n;
- else
- return false;
}
+ else
+ n = GetNextSibling (n);
+ if (n == null)
+ return false;
+ node = n;
return true;
}
// But if scope is Local, then it returns false here.
if (namespaceScope == XPathNamespaceScope.Local)
return false;
- owner = owner.ParentNode as XmlElement;
+ owner = GetParentNode (owner) as XmlElement;
while (owner != null) {
- for (int i = 0; i < owner.Attributes.Count; i++) {
- XmlAttribute attr = owner.Attributes [i];
- if (attr.NamespaceURI == Xmlns) {
- if (CheckNsNameAppearance (attr.Name, attr.Value))
- continue;
- NsNode = attr;
- return true;
+ if (owner.HasAttributes) {
+ for (int i = 0; i < owner.Attributes.Count; i++) {
+ XmlAttribute attr = owner.Attributes [i];
+ if (attr.NamespaceURI == Xmlns) {
+ if (CheckNsNameAppearance (attr.Name, attr.Value))
+ continue;
+ NsNode = attr;
+ return true;
+ }
}
}
- owner = owner.ParentNode as XmlElement;
+ owner = GetParentNode (owner) as XmlElement;
}
if (namespaceScope == XPathNamespaceScope.All) {
NsNode = null;
return true;
}
- } else if (node.ParentNode != null) {
- node = node.ParentNode;
- NsNode = null;
- return true;
+ else
+ return false;
}
- return false;
+ XmlNode n = GetParentNode (node);
+ if (n == null)
+ return false;
+ node = n;
+ NsNode = null;
+ return true;
}
public override bool MoveToPrevious ()
if (NsNode != null)
return false;
- if (node.PreviousSibling != null) {
- if (node.ParentNode != null && node.ParentNode.NodeType == XmlNodeType.Document) {
- XmlNode n = node.PreviousSibling;
- while (n != null) {
- switch (n.NodeType) {
- case XmlNodeType.DocumentType:
- case XmlNodeType.XmlDeclaration:
- n = n.PreviousSibling;
- continue;
- }
- break;
- }
- if (n != null)
- node = n;
- else
- return false;
- }
- else
- node = node.PreviousSibling;
-
- return true;
- }
- else
+ XmlNode p = GetPreviousSibling (node);
+ if (p == null)
return false;
+ node = p;
+ return true;
}
public override void MoveToRoot ()
{
XmlAttribute attr = node as XmlAttribute;
XmlNode tmp = attr != null ? attr.OwnerElement : node;
- while (tmp.ParentNode != null)
- tmp = tmp.ParentNode;
+ for (XmlNode tmp2 = GetParentNode (tmp); tmp2 != null; tmp2 = GetParentNode (tmp2))
+ tmp = tmp2;
node = tmp;
NsNode = null;
}
- internal XmlNode Node { get { return NsNode != null ? NsNode : node; } }
+ private XmlNode Node { get { return NsNode != null ? NsNode : node; } }
+
+ XmlNode IHasXmlNode.GetNode ()
+ {
+ return Node;
+ }
+
+ private XmlNode GetFirstChild (XmlNode n)
+ {
+ if (n.FirstChild == null)
+ return null;
+ switch (n.FirstChild.NodeType) {
+ case XmlNodeType.XmlDeclaration:
+ case XmlNodeType.DocumentType:
+ return GetNextSibling (n.FirstChild);
+ case XmlNodeType.EntityReference:
+ foreach (XmlNode c in n.ChildNodes) {
+ if (c.NodeType == XmlNodeType.EntityReference) {
+ XmlNode ec = GetFirstChild (c);
+ if (ec != null)
+ return ec;
+ }
+ return c;
+ }
+ return null;
+ default:
+ return n.FirstChild;
+ }
+ }
+
+ private XmlNode GetLastChild (XmlNode n)
+ {
+ if (n.LastChild == null)
+ return null;
+ switch (n.LastChild.NodeType) {
+ case XmlNodeType.XmlDeclaration:
+ case XmlNodeType.DocumentType:
+ return GetPreviousSibling (n.LastChild);
+ case XmlNodeType.EntityReference:
+ for (XmlNode c = n.LastChild; c != null; c = c.PreviousSibling) {
+ if (c.NodeType == XmlNodeType.EntityReference) {
+ XmlNode ec = GetLastChild (c);
+ if (ec != null)
+ return ec;
+ }
+ return c;
+ }
+ return null;
+ default:
+ return n.LastChild;
+ }
+ }
+
+ private XmlNode GetPreviousSibling (XmlNode n)
+ {
+ XmlNode p = n.PreviousSibling;
+ if (p != null) {
+ switch (p.NodeType) {
+ case XmlNodeType.EntityReference:
+ XmlNode c = GetLastChild (p);
+ if (c != null)
+ return c;
+ else // empty entity reference etc.
+ return GetPreviousSibling (p);
+ case XmlNodeType.XmlDeclaration:
+ case XmlNodeType.DocumentType:
+ return GetPreviousSibling (p);
+ default:
+ return p;
+ }
+ } else {
+ if (n.ParentNode == null || n.ParentNode.NodeType != XmlNodeType.EntityReference)
+ return null;
+ return GetPreviousSibling (n.ParentNode);
+ }
+ }
+
+ private XmlNode GetNextSibling (XmlNode n)
+ {
+ XmlNode nx = n.NextSibling;
+ if (nx != null) {
+ switch (nx.NodeType) {
+ case XmlNodeType.EntityReference:
+ XmlNode c = GetFirstChild (nx);
+ if (c != null)
+ return c;
+ else // empty entity reference etc.
+ return GetNextSibling (nx);
+ case XmlNodeType.XmlDeclaration:
+ case XmlNodeType.DocumentType:
+ return GetNextSibling (nx);
+ default:
+ return n.NextSibling;
+ }
+ } else {
+ if (n.ParentNode == null || n.ParentNode.NodeType != XmlNodeType.EntityReference)
+ return null;
+ return GetNextSibling (n.ParentNode);
+ }
+ }
- XmlNode IHasXmlNode.GetNode ()
- {
- return node;
- }
+ private XmlNode GetParentNode (XmlNode n)
+ {
+ if (n.ParentNode == null)
+ return null;
+ for (XmlNode p = n.ParentNode; p != null; p = p.ParentNode)
+ if (p.NodeType != XmlNodeType.EntityReference)
+ return p;
+ return null;
+ }
#endregion
}