2003-10-25 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[mono.git] / mcs / class / System.XML / System.Xml / XmlAttribute.cs
index 56e8658f4d5f13187d0c6929b9e87d3a117254d9..ba60b74589eabad38c4bcc993d1d1e3e697efcf4 100644 (file)
@@ -1,14 +1,17 @@
 //
 // System.Xml.XmlAttribute
 //
-// Author:
+// Authors:
 //   Jason Diamond (jason@injektilo.org)
+//   Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
 //
 // (C) 2002 Jason Diamond  http://injektilo.org/
+// (C) 2003 Atsushi Enomoto
 //
 
 using System;
 using System.Text;
+using System.Xml.XPath;
 
 namespace System.Xml
 {
@@ -20,18 +23,39 @@ namespace System.Xml
                private string localName;
                private string namespaceURI;
                private string prefix;
+               internal bool isDefault;
+               private XmlElement ownerElement;
 
                #endregion
 
                #region Constructor
 
-               [MonoTODO("need to set namespaceURI if prefix is recognized built-in ones like xmlns")]
                protected internal XmlAttribute (
                        string prefix, 
                        string localName, 
-                       string namespaceURI, 
+                       string namespaceURI,
                        XmlDocument doc) : base (doc)
                {
+                       if (prefix == null)
+                               prefix = String.Empty;
+                       if (namespaceURI == null)
+                               namespaceURI = String.Empty;
+
+                       // Prefix "xml" should be also checked (http://www.w3.org/XML/xml-names-19990114-errata#NE05)
+                       // but MS.NET ignores such case.
+                       if (prefix == "xmlns" || (prefix == "" && localName == "xmlns"))
+                               if (namespaceURI != XmlNamespaceManager.XmlnsXmlns)
+                                       throw new ArgumentException ("Invalid attribute namespace for namespace declaration.");
+                       else if (prefix == "xml" && namespaceURI != XmlNamespaceManager.XmlnsXml)
+                                       throw new ArgumentException ("Invalid attribute namespace for namespace declaration.");
+
+                       // There are no means to identify the DOM is namespace-
+                       // aware or not, so we can only check Name validity.
+                       if (prefix != "" && !XmlChar.IsName (prefix))
+                               throw new ArgumentException ("Invalid attribute prefix.");
+                       else if (!XmlChar.IsName (localName))
+                               throw new ArgumentException ("Invalid attribute local name.");
+
                        this.prefix = prefix;
                        this.localName = localName;
                        this.namespaceURI = namespaceURI;
@@ -47,31 +71,16 @@ namespace System.Xml
                        }
                }
 
-               [MonoTODO ("Setter")]
                public override string InnerText {
                        get {
-                               StringBuilder builder = new StringBuilder ();
-                               AppendChildValues (this, builder);
-                               return builder.ToString ();
-                        }
+                               return base.InnerText;
+                       }
 
                        set {
-                               throw new NotImplementedException ();
+                               Value = value;
                        }
                }
 
-               private void AppendChildValues (XmlNode parent, StringBuilder builder)
-               {
-                       XmlNode node = parent.FirstChild;
-                       
-                       while (node != null) {
-                               builder.Append (node.Value);
-                               AppendChildValues (node, builder);
-                               node = node.NextSibling;
-                        }
-                }
-               
-               [MonoTODO ("Setter.")]
                public override string InnerXml {
                        get {
                                // Not sure why this is an override.  Passing through for now.
@@ -79,7 +88,15 @@ namespace System.Xml
                        }
 
                        set {
-                               throw new NotImplementedException ();
+                               RemoveAll ();
+                               XmlNamespaceManager nsmgr = ConstructNamespaceManager ();
+                               XmlParserContext ctx = new XmlParserContext (OwnerDocument.NameTable, nsmgr,
+                                       OwnerDocument.DocumentType != null ? OwnerDocument.DocumentType.DTD : null,
+                                       BaseURI, XmlLang, XmlSpace, null);
+                               XmlTextReader xtr = new XmlTextReader (value, XmlNodeType.Attribute, ctx);
+                               xtr.XmlResolver = OwnerDocument.Resolver;
+                               xtr.Read ();
+                               OwnerDocument.ReadAttributeNodeValue (xtr, this);
                        }
                }
 
@@ -107,6 +124,12 @@ namespace System.Xml
                        }
                }
 
+               internal override XPathNodeType XPathNodeType {
+                       get {
+                               return XPathNodeType.Attribute;
+                       }
+               }
+
                public override XmlDocument OwnerDocument {
                        get {
                                return base.OwnerDocument;
@@ -115,23 +138,30 @@ namespace System.Xml
 
                public virtual XmlElement OwnerElement {
                        get {
-                               return base.ParentNode as XmlElement;
+                               return ownerElement;
                        }
                }
 
-               [MonoTODO]
                public override XmlNode ParentNode {
                        get {
+                               // It always returns null (by specification).
                                return null;
                        }
                }
 
-               [MonoTODO]
                // We gotta do more in the set block here
                // We need to do the proper tests and throw
                // the correct Exceptions
+               //
+               // Wrong cases are: (1)check readonly, (2)check character validity,
+               // (3)check format validity, (4)this is attribute and qualifiedName != "xmlns"
                public override string Prefix {
                        set {
+                               if (IsReadOnly)
+                                       throw new XmlException ("This node is readonly.");
+                               if (!XmlChar.IsNCName (value))
+                                       throw new ArgumentException ("Specified name is not a valid NCName: " + value);
+
                                prefix = value;
                        }
                        
@@ -140,10 +170,9 @@ namespace System.Xml
                        }
                }
 
-               [MonoTODO]
                public virtual bool Specified {
                        get {
-                               throw new NotImplementedException ();
+                               return !isDefault;
                        }
                }
 
@@ -159,11 +188,23 @@ namespace System.Xml
                                XmlNode firstChild = FirstChild;
                                if (firstChild == null)
                                        AppendChild (OwnerDocument.CreateTextNode (value));
+                               else if (FirstChild.NextSibling != null) {
+                                       this.RemoveAll ();
+                                       AppendChild (OwnerDocument.CreateTextNode (value));
+                               }
                                else
                                        firstChild.Value = value;
                        }
                }
 
+               internal override string XmlLang {
+                       get { return OwnerElement.XmlLang; }
+               }
+
+               internal override XmlSpace XmlSpace {
+                       get { return OwnerElement.XmlSpace; }
+               }
+
                #endregion
 
                #region Methods
@@ -173,23 +214,34 @@ namespace System.Xml
                        XmlNode node = new XmlAttribute (prefix, localName, namespaceURI,
                                                         OwnerDocument);
                        if (deep) {
-                               while ((node != null) && (node.HasChildNodes)) {
-                                       AppendChild (node.NextSibling.CloneNode (true));
-                                       node = node.NextSibling;
-                               }
+                               foreach (XmlNode child in this.ChildNodes)
+                                       node.AppendChild (child.CloneNode (deep));
                        }
 
                        return node;
                }
 
+               internal void SetDefault ()
+               {
+                       isDefault = true;
+               }
+
+               // Parent of XmlAttribute must be null
+               internal void SetOwnerElement (XmlElement el) {
+                       ownerElement = el;
+               }
+
                public override void WriteContentTo (XmlWriter w)
                {
-                       w.WriteString (Value);
+                       foreach (XmlNode n in ChildNodes)
+                               n.WriteTo (w);
                }
 
                public override void WriteTo (XmlWriter w)
                {
-                       w.WriteAttributeString (prefix, localName, namespaceURI, Value);
+                       w.WriteStartAttribute (prefix, localName, namespaceURI);
+                       WriteContentTo (w);
+                       w.WriteEndAttribute ();
                }
 
                #endregion