5 // Copyright 2007 Novell (http://www.novell.com)
6 // Copyright 2011 Xamarin Inc (http://www.xamarin.com).
8 // Permission is hereby granted, free of charge, to any person obtaining
9 // a copy of this software and associated documentation files (the
10 // "Software"), to deal in the Software without restriction, including
11 // without limitation the rights to use, copy, modify, merge, publish,
12 // distribute, sublicense, and/or sell copies of the Software, and to
13 // permit persons to whom the Software is furnished to do so, subject to
14 // the following conditions:
16 // The above copyright notice and this permission notice shall be
17 // included in all copies or substantial portions of the Software.
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using XPI = System.Xml.Linq.XProcessingInstruction;
33 namespace System.Xml.Linq
35 internal class XNodeReader : XmlReader, IXmlLineInfo
37 ReadState state = ReadState.Initial;
42 NameTable name_table = new NameTable ();
44 public XNodeReader (XNode node)
51 internal bool OmitDuplicateNamespaces { get; set; }
54 int IXmlLineInfo.LineNumber {
56 var o = (XObject) GetCurrentAttribute () ?? node;
57 return o != null ? o.LineNumber : 0;
60 int IXmlLineInfo.LinePosition {
62 var o = (XObject) GetCurrentAttribute () ?? node;
63 return o != null ? o.LinePosition : 0;
66 bool IXmlLineInfo.HasLineInfo ()
68 var o = (XObject) GetCurrentAttribute () ?? node;
69 return o != null ? ((IXmlLineInfo) o).HasLineInfo () : false;
72 public override int AttributeCount {
74 if (state != ReadState.Interactive || end_element)
77 switch (node.NodeType) {
78 case XmlNodeType.Document: // this means xmldecl
79 XDeclaration xd = ((XDocument) node).Declaration;
80 i = (xd.Version != null ? 1 : 0) +
81 (xd.Encoding != null ? 1 : 0) +
82 (xd.Standalone != null ? 1 : 0);
84 case XmlNodeType.DocumentType:
85 XDocumentType dtd = (XDocumentType) node;
86 i = (dtd.PublicId != null ? 1 : 0) +
87 (dtd.SystemId != null ? 1 : 0) +
88 (dtd.InternalSubset != null ? 1 : 0);
90 case XmlNodeType.Element:
91 XElement el = (XElement) node;
92 for (XAttribute a = el.FirstAttribute; a != null; a = a.NextAttribute)
100 public override string BaseURI {
101 get { return node.BaseUri ?? String.Empty; }
104 public override int Depth {
109 // document.Depth = 0, root.Depth = 0, others.Depth = they depend
110 for (XNode n = node.Parent; n != null; n = n.Parent)
120 public override bool EOF {
121 get { return state == ReadState.EndOfFile || state == ReadState.Error; }
124 public override bool HasAttributes {
126 if (EOF || end_element || node == null)
129 if (node is XElement)
130 return ((XElement) node).HasAttributes;
131 return AttributeCount > 0;
135 public override bool HasValue {
141 switch (node.NodeType) {
142 case XmlNodeType.Element:
143 case XmlNodeType.Document:
144 case XmlNodeType.EndElement:
152 public override bool IsEmptyElement {
153 get { return !EOF && attr < 0 && node is XElement ? ((XElement) node).IsEmpty : false; }
156 internal XAttribute GetCurrentAttribute ()
158 return GetXAttribute (attr);
161 XAttribute GetXAttribute (int idx)
165 XElement el = node as XElement;
169 foreach (XAttribute a in el.Attributes ())
175 // XName for element and attribute, string for xmldecl attributes, doctype attribute, doctype name and PI, null for empty.
176 object GetCurrentName ()
178 if (EOF || attr_value)
180 return GetName (attr);
183 object GetName (int attr)
186 switch (node.NodeType) {
187 case XmlNodeType.Element:
188 XAttribute a = GetXAttribute (attr);
190 case XmlNodeType.DocumentType:
192 return ((XDocumentType) node).PublicId != null ? "PUBLIC" : "SYSTEM";
194 case XmlNodeType.Document:
195 XDeclaration xd = ((XDocument) node).Declaration;
198 return xd.Version != null ? "version" : xd.Encoding != null ? "encoding" : "standalone";
200 return xd.Version != null ? (xd.Encoding != null ? "encoding" : "standalone") : "standalone";
205 switch (node.NodeType) {
206 case XmlNodeType.Document:
207 return "xml"; // xmldecl
208 case XmlNodeType.Element:
209 return ((XElement) node).Name;
210 case XmlNodeType.ProcessingInstruction:
211 return ((XPI) node).Target;
212 case XmlNodeType.DocumentType:
213 return ((XDocumentType) node).Name;
219 public override string LocalName {
221 object name = GetCurrentName ();
225 return (string) name;
226 return ((XName) name).LocalName;
230 public override string NamespaceURI {
232 XName name = GetCurrentName () as XName;
234 // XName for "xmlns" has NamespaceName as "", so we have to return w3c xmlns as a special case.
235 return name.LocalName == "xmlns" && name.Namespace == XNamespace.None ?
236 XNamespace.Xmlns.NamespaceName :
242 public override XmlNameTable NameTable {
243 get { return name_table; }
246 public override XmlNodeType NodeType {
248 return state != ReadState.Interactive ? XmlNodeType.None :
249 end_element ? XmlNodeType.EndElement :
250 attr_value ? XmlNodeType.Text :
251 attr >= 0 ? XmlNodeType.Attribute :
252 node.NodeType == XmlNodeType.Document ? XmlNodeType.XmlDeclaration :
257 public override string Prefix {
259 XName name = GetCurrentName () as XName;
260 if (name == null || name.Namespace == XNamespace.None)
262 XElement el = (node as XElement) ?? node.Parent;
265 return el.GetPrefixOfNamespace (name.Namespace) ?? String.Empty;
269 public override ReadState ReadState {
270 get { return state; }
273 public override string Value {
275 if (ReadState != ReadState.Interactive)
277 XAttribute a = GetCurrentAttribute ();
280 switch (node.NodeType) {
281 case XmlNodeType.Document:
282 XDeclaration xd = ((XDocument) node).Declaration;
290 return xd.Standalone;
293 string s = xd.ToString ();
294 return s.Substring (6, s.Length - 6 - 2);
296 case XmlNodeType.DocumentType:
297 XDocumentType dtd = (XDocumentType) node;
304 return dtd.InternalSubset;
306 case XmlNodeType.ProcessingInstruction:
307 return ((XPI) node).Data;
308 case XmlNodeType.CDATA:
309 case XmlNodeType.Text:
310 return ((XText) node).Value;
311 case XmlNodeType.Comment:
312 return ((XComment) node).Value;
318 public override void Close ()
320 state = ReadState.Closed;
323 public override string LookupNamespace (string prefix)
327 XElement el = (node as XElement) ?? node.Parent;
330 var xn = el.GetNamespaceOfPrefix (prefix);
331 return xn != XNamespace.None ? xn.NamespaceName : null;
334 public override bool MoveToElement ()
344 public override bool MoveToFirstAttribute ()
346 if (AttributeCount > 0) {
354 public override bool MoveToNextAttribute ()
356 int c = AttributeCount;
365 public override bool MoveToAttribute (string name)
368 throw new ArgumentNullException ("name");
370 int c = AttributeCount;
372 for (int i = 0; i < c; i++) {
373 object o = GetName (i);
376 if ((o as string) == name)
379 if (name.EndsWith (n.LocalName, StringComparison.Ordinal) && name == GetPrefixedName ((XName) o))
390 string GetPrefixedName (XName name)
392 XElement el = (node as XElement) ?? node.Parent;
394 name.Namespace == XNamespace.None ||
395 el.GetPrefixOfNamespace (name.Namespace) == String.Empty)
396 return name.LocalName;
397 return String.Concat (el.GetPrefixOfNamespace (name.Namespace), ":", name.LocalName);
400 public override bool MoveToAttribute (string local, string ns)
403 throw new ArgumentNullException ("local");
405 throw new ArgumentNullException ("ns");
407 int c = AttributeCount;
409 for (int i = 0; i < c; i++) {
410 object o = GetName (i);
413 if ((o as string) == local && ns.Length == 0)
416 if (local == n.LocalName && ns == n.NamespaceName)
427 public override string GetAttribute (int i)
430 bool av_bak = attr_value;
441 public override string GetAttribute (string name)
444 bool av_bak = attr_value;
447 return MoveToAttribute (name) ? Value : null;
454 public override string GetAttribute (string local, string ns)
457 bool av_bak = attr_value;
460 return MoveToAttribute (local, ns) ? Value : null;
467 public override bool Read ()
469 // clear attribute state on element/xmldecl/dtd.
474 case ReadState.Initial:
475 state = ReadState.Interactive;
476 XDocument doc = node as XDocument;
478 if (doc.Declaration != null)
482 return true; // any other root
484 case ReadState.Interactive:
490 // when positioned on xmldecl, move to children
491 if (node is XDocument) {
492 XDocument doc = node as XDocument;
493 node = doc.FirstNode;
495 state = ReadState.EndOfFile;
498 node = doc.FirstNode;
502 XElement c = node as XElement;
503 if (c != null && !end_element) {
504 if (c.FirstNode != null) {
507 } else if (!c.IsEmpty) {
508 // empty but full EndElement
514 if (node.NextNode != null && node != start) {
515 node = node.NextNode;
518 if (node.Parent == null || node == start) {
519 state = ReadState.EndOfFile;
529 bool ReadAttributeValue ()
531 if (attr < 0 || attr_value)
537 public override void ResolveEntity ()
539 throw new NotSupportedException ();
542 // Note that this does not return attribute node.
543 internal XNode CurrentNode {