2003-10-04 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[mono.git] / mcs / class / System.XML / System.Xml / XmlAttribute.cs
1 //
2 // System.Xml.XmlAttribute
3 //
4 // Authors:
5 //   Jason Diamond (jason@injektilo.org)
6 //   Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 //
8 // (C) 2002 Jason Diamond  http://injektilo.org/
9 // (C) 2003 Atsushi Enomoto
10 //
11
12 using System;
13 using System.Text;
14 using System.Xml.XPath;
15
16 namespace System.Xml
17 {
18         public class XmlAttribute : XmlNode
19         {
20                 #region Fields
21
22                 private XmlLinkedNode lastChild;
23                 private string localName;
24                 private string namespaceURI;
25                 private string prefix;
26                 internal bool isDefault;
27                 private XmlElement ownerElement;
28
29                 #endregion
30
31                 #region Constructor
32
33                 protected internal XmlAttribute (
34                         string prefix, 
35                         string localName, 
36                         string namespaceURI,
37                         XmlDocument doc) : base (doc)
38                 {
39                         if (prefix == null)
40                                 prefix = String.Empty;
41                         if (namespaceURI == null)
42                                 namespaceURI = String.Empty;
43
44                         // Prefix "xml" should be also checked (http://www.w3.org/XML/xml-names-19990114-errata#NE05)
45                         // but MS.NET ignores such case.
46                         if (prefix == "xmlns" || (prefix == "" && localName == "xmlns"))
47                                 if (namespaceURI != XmlNamespaceManager.XmlnsXmlns)
48                                         throw new ArgumentException ("Invalid attribute namespace for namespace declaration.");
49                         else if (prefix == "xml" && namespaceURI != XmlNamespaceManager.XmlnsXml)
50                                         throw new ArgumentException ("Invalid attribute namespace for namespace declaration.");
51
52                         // There are no means to identify the DOM is namespace-
53                         // aware or not, so we can only check Name validity.
54                         if (prefix != "" && !XmlChar.IsName (prefix))
55                                 throw new ArgumentException ("Invalid attribute prefix.");
56                         else if (!XmlChar.IsName (localName))
57                                 throw new ArgumentException ("Invalid attribute local name.");
58
59                         this.prefix = prefix;
60                         this.localName = localName;
61                         this.namespaceURI = namespaceURI;
62                 }
63
64                 #endregion
65
66                 #region Properties
67
68                 public override string BaseURI {
69                         get {
70                                 return OwnerElement.BaseURI;
71                         }
72                 }
73
74                 public override string InnerText {
75                         get {
76                                 return base.InnerText;
77                         }
78
79                         set {
80                                 Value = value;
81                         }
82                 }
83
84                 public override string InnerXml {
85                         get {
86                                 // Not sure why this is an override.  Passing through for now.
87                                 return base.InnerXml;
88                         }
89
90                         set {
91                                 RemoveAll ();
92                                 XmlNamespaceManager nsmgr = ConstructNamespaceManager ();
93                                 XmlParserContext ctx = new XmlParserContext (OwnerDocument.NameTable, nsmgr,
94                                         OwnerDocument.DocumentType != null ? OwnerDocument.DocumentType.DTD : null,
95                                         BaseURI, XmlLang, XmlSpace, null);
96                                 XmlTextReader xtr = new XmlTextReader (value, XmlNodeType.Attribute, ctx);
97                                 xtr.XmlResolver = OwnerDocument.Resolver;
98                                 xtr.Read ();
99                                 OwnerDocument.ReadAttributeNodeValue (xtr, this);
100                         }
101                 }
102
103                 public override string LocalName {
104                         get {
105                                 return localName;
106                         }
107                 }
108
109                 public override string Name {
110                         get { 
111                                 return prefix != String.Empty ? prefix + ":" + localName : localName; 
112                         }
113                 }
114
115                 public override string NamespaceURI {
116                         get {
117                                 return namespaceURI;
118                         }
119                 }
120
121                 public override XmlNodeType NodeType {
122                         get {
123                                 return XmlNodeType.Attribute;
124                         }
125                 }
126
127                 internal override XPathNodeType XPathNodeType {
128                         get {
129                                 return XPathNodeType.Attribute;
130                         }
131                 }
132
133                 public override XmlDocument OwnerDocument {
134                         get {
135                                 return base.OwnerDocument;
136                         }
137                 }
138
139                 public virtual XmlElement OwnerElement {
140                         get {
141                                 return ownerElement;
142                         }
143                 }
144
145                 public override XmlNode ParentNode {
146                         get {
147                                 // It always returns null (by specification).
148                                 return null;
149                         }
150                 }
151
152                 // We gotta do more in the set block here
153                 // We need to do the proper tests and throw
154                 // the correct Exceptions
155                 //
156                 // Wrong cases are: (1)check readonly, (2)check character validity,
157                 // (3)check format validity, (4)this is attribute and qualifiedName != "xmlns"
158                 public override string Prefix {
159                         set {
160                                 if (IsReadOnly)
161                                         throw new XmlException ("This node is readonly.");
162                                 if (!XmlChar.IsNCName (value))
163                                         throw new ArgumentException ("Specified name is not a valid NCName: " + value);
164
165                                 prefix = value;
166                         }
167                         
168                         get {
169                                 return prefix;
170                         }
171                 }
172
173                 public virtual bool Specified {
174                         get {
175                                 return !isDefault;
176                         }
177                 }
178
179                 public override string Value {
180                         get {
181                                 XmlNode firstChild = FirstChild;
182                                 if (firstChild == null)
183                                         return String.Empty;
184                                 return firstChild.Value;
185                         }
186
187                         set {
188                                 XmlNode firstChild = FirstChild;
189                                 if (firstChild == null)
190                                         AppendChild (OwnerDocument.CreateTextNode (value));
191                                 else
192                                         firstChild.Value = value;
193                         }
194                 }
195
196                 internal override string XmlLang {
197                         get { return OwnerElement.XmlLang; }
198                 }
199
200                 internal override XmlSpace XmlSpace {
201                         get { return OwnerElement.XmlSpace; }
202                 }
203
204                 #endregion
205
206                 #region Methods
207
208                 public override XmlNode CloneNode (bool deep)
209                 {
210                         XmlNode node = new XmlAttribute (prefix, localName, namespaceURI,
211                                                          OwnerDocument);
212                         if (deep) {
213                                 foreach (XmlNode child in this.ChildNodes)
214                                         node.AppendChild (child.CloneNode (deep));
215                         }
216
217                         return node;
218                 }
219
220                 internal void SetDefault ()
221                 {
222                         isDefault = true;
223                 }
224
225                 // Parent of XmlAttribute must be null
226                 internal void SetOwnerElement (XmlElement el) {
227                         ownerElement = el;
228                 }
229
230                 public override void WriteContentTo (XmlWriter w)
231                 {
232                         foreach (XmlNode n in ChildNodes)
233                                 n.WriteTo (w);
234                 }
235
236                 public override void WriteTo (XmlWriter w)
237                 {
238                         w.WriteStartAttribute (prefix, localName, namespaceURI);
239                         WriteContentTo (w);
240                         w.WriteEndAttribute ();
241                 }
242
243                 #endregion
244
245                 internal override XmlLinkedNode LastLinkedChild {
246                         get { return lastChild; }
247
248                         set { lastChild = value; }
249                 }
250         }
251 }