2003-10-25 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[mono.git] / mcs / class / System.XML / System.Xml / XmlAttribute.cs
index a918bac0ad0cee5f67f52863ab5704c5a2a95844..ba60b74589eabad38c4bcc993d1d1e3e697efcf4 100644 (file)
@@ -1,10 +1,12 @@
 //
 // 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;
@@ -28,15 +30,32 @@ namespace System.Xml
 
                #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)
                {
-                       // What to be recognized is: xml:space, xml:lang, xml:base, and
-                       // xmlns and xmlns:* (when XmlDocument.Namespaces = true only)
+                       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;
@@ -54,28 +73,14 @@ namespace System.Xml
 
                public override string InnerText {
                        get {
-                               StringBuilder builder = new StringBuilder ();
-                               AppendChildValues (this, builder);
-                               return builder.ToString ();
-                        }
+                               return base.InnerText;
+                       }
 
                        set {
                                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 is incomplete(XmlTextReader.ReadAttribute is incomplete;No resolution for xml:lang/space")]
                public override string InnerXml {
                        get {
                                // Not sure why this is an override.  Passing through for now.
@@ -83,11 +88,14 @@ namespace System.Xml
                        }
 
                        set {
+                               RemoveAll ();
                                XmlNamespaceManager nsmgr = ConstructNamespaceManager ();
-                               XmlParserContext ctx = new XmlParserContext (OwnerDocument.NameTable, nsmgr, XmlLang, this.XmlSpace);
-                               XmlTextReader xtr = OwnerDocument.ReusableReader;
-                               xtr.Initialize (BaseURI, ctx, new System.IO.StringReader ("'" + value.Replace ("'", "&apos;") + "'"), XmlNodeType.Attribute);
-
+                               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);
                        }
                }
@@ -141,23 +149,18 @@ namespace System.Xml
                        }
                }
 
-               [MonoTODO("setter incomplete (name character check, format check, wrong prefix&nsURI)")]
                // 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"
-               // (5)when argument is 'xml' or 'xmlns' and namespaceURI doesn't match
                public override string Prefix {
                        set {
-                               if(IsReadOnly)
+                               if (IsReadOnly)
                                        throw new XmlException ("This node is readonly.");
-
-                               XmlNamespaceManager nsmgr = ConstructNamespaceManager ();
-                               string nsuri = nsmgr.LookupNamespace (value);
-                               if(nsuri == null)
-                                       throw new XmlException ("Namespace URI not found for this prefix");
+                               if (!XmlChar.IsNCName (value))
+                                       throw new ArgumentException ("Specified name is not a valid NCName: " + value);
 
                                prefix = value;
                        }
@@ -167,7 +170,6 @@ namespace System.Xml
                        }
                }
 
-               [MonoTODO("There are no code which sets 'specified = true', so this logic is without checking.")]
                public virtual bool Specified {
                        get {
                                return !isDefault;
@@ -186,6 +188,10 @@ 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;
                        }
@@ -208,15 +214,18 @@ 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;