1
// Copyright (c) 2009-2013 AlphaSierraPapa for the SharpDevelop Team
3
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4
// software and associated documentation files (the "Software"), to deal in the Software
5
// without restriction, including without limitation the rights to use, copy, modify, merge,
6
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7
// to whom the Software is furnished to do so, subject to the following conditions:
9
// The above copyright notice and this permission notice shall be included in all copies or
10
// substantial portions of the Software.
12
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17
// DEALINGS IN THE SOFTWARE.
20
using System.Collections.Generic;
21
using System.Globalization;
24
namespace ICSharpCode.NRefactory.Xml
29
public class AXmlElement : AXmlObject
31
internal AXmlElement(AXmlObject parent, int startOffset, InternalElement internalObject)
32
: base(parent, startOffset, internalObject)
34
Log.Assert(internalObject.NestedObjects[0] is InternalTag, "First child of element must be start tag");
37
/// <summary> No tags are missing anywhere within this element (recursive) </summary>
38
public bool IsProperlyNested {
39
get { return ((InternalElement)internalObject).IsPropertyNested; }
42
/// <summary>The start or empty-element tag for this element.</summary>
43
public AXmlTag StartTag {
44
get { return (AXmlTag)this.Children[0]; }
47
/// <summary>Name with namespace prefix - exactly as in source</summary>
49
get { return ((InternalTag)internalObject.NestedObjects[0]).Name; }
52
/// <summary>Gets whether an end tag exists for this node.</summary>
53
public bool HasEndTag {
54
get { return ((InternalElement)internalObject).HasEndTag; }
57
/// <summary> The end tag, if there is any. Returns null for empty elements "<Element/>" and missing end tags in malformed XML.</summary>
58
public AXmlTag EndTag {
61
return (AXmlTag)this.Children[this.Children.Count - 1];
68
/// Gets the attributes.
70
public IEnumerable<AXmlAttribute> Attributes {
72
return ((AXmlTag)this.Children[0]).Children.OfType<AXmlAttribute>();
77
/// Gets the content (all children except for the start and end tags)
79
public IEnumerable<AXmlObject> Content {
81
int end = this.Children.Count;
84
for (int i = 1; i < end; i++) {
85
yield return this.Children[i];
90
/// <summary> The part of name before ":" </summary>
91
/// <returns> Empty string if not found </returns>
92
public string Prefix {
93
get { return ((InternalElement)internalObject).Prefix; }
96
/// <summary> The part of name after ":" </summary>
97
/// <returns> Empty string if not found </returns>
98
public string LocalName {
99
get { return ((InternalElement)internalObject).LocalName; }
102
/// <summary> Resolved namespace of the name </summary>
103
/// <returns> Empty string if prefix is not found </returns>
104
public string Namespace {
106
string prefix = this.Prefix;
107
return ResolvePrefix(prefix);
111
/// <summary> Find the defualt namespace for this context </summary>
112
public string FindDefaultNamespace()
114
return ResolvePrefix(string.Empty);
118
/// Recursively resolve given prefix in this context. Prefix must have some value.
120
/// <returns> Empty string if prefix is not found </returns>
121
public string ResolvePrefix(string prefix)
124
throw new ArgumentNullException("prefix");
126
// Implicit namesapces
127
if (prefix == "xml") return XmlNamespace;
128
if (prefix == "xmlns") return XmlnsNamespace;
130
string lookFor = (prefix.Length > 0 ? "xmlns:" + prefix : "xmlns");
131
for (AXmlElement current = this; current != null; current = current.Parent as AXmlElement) {
132
foreach (var attr in current.Attributes) {
133
if (attr.Name == lookFor)
137
return NoNamespace; // Can not find prefix
141
/// Get unquoted value of attribute.
142
/// It looks in the no namespace (empty string).
144
/// <returns>Null if not found</returns>
145
public string GetAttributeValue(string localName)
147
return GetAttributeValue(NoNamespace, localName);
151
/// Get unquoted value of attribute
153
/// <param name="namespace">Namespace. Can be no namepace (empty string), which is the default for attributes.</param>
154
/// <param name="localName">Local name - text after ":"</param>
155
/// <returns>Null if not found</returns>
156
public string GetAttributeValue(string @namespace, string localName)
158
@namespace = @namespace ?? string.Empty;
159
foreach (AXmlAttribute attr in this.Attributes) {
160
if (attr.LocalName == localName && attr.Namespace == @namespace)
167
public override void AcceptVisitor(AXmlVisitor visitor)
169
visitor.VisitElement(this);
173
public override string ToString()
175
return string.Format(CultureInfo.InvariantCulture, "[{0} '{1}' Attr:{2} Chld:{3} Nest:{4}]", base.ToString(), this.Name, this.StartTag.Children.Count, this.Children.Count, this.IsProperlyNested ? "Ok" : "Bad");