Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/xamarin/NRefactory.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Grunwald <daniel@danielgrunwald.de>2013-04-26 22:17:13 +0400
committerDaniel Grunwald <daniel@danielgrunwald.de>2013-05-08 20:36:55 +0400
commit7f24e36cfde7ad999e25f0acae367820e547197c (patch)
treeaafa1e1b27dbec92e65803cb2b21322c182e32b0 /ICSharpCode.NRefactory.Xml
parent6e5560a6b911058ac7022ed6bc0bafd71a95a08c (diff)
Fix handling of empty elements in AXmlReader; and add support for comments.
Diffstat (limited to 'ICSharpCode.NRefactory.Xml')
-rw-r--r--ICSharpCode.NRefactory.Xml/AXmlAttribute.cs2
-rw-r--r--ICSharpCode.NRefactory.Xml/AXmlDocument.cs12
-rw-r--r--ICSharpCode.NRefactory.Xml/AXmlElement.cs81
-rw-r--r--ICSharpCode.NRefactory.Xml/AXmlObject.cs53
-rw-r--r--ICSharpCode.NRefactory.Xml/AXmlReader.cs40
-rw-r--r--ICSharpCode.NRefactory.Xml/TagReader.cs2
6 files changed, 156 insertions, 34 deletions
diff --git a/ICSharpCode.NRefactory.Xml/AXmlAttribute.cs b/ICSharpCode.NRefactory.Xml/AXmlAttribute.cs
index 8af65aff..9fe13856 100644
--- a/ICSharpCode.NRefactory.Xml/AXmlAttribute.cs
+++ b/ICSharpCode.NRefactory.Xml/AXmlAttribute.cs
@@ -90,7 +90,7 @@ namespace ICSharpCode.NRefactory.Xml
AXmlElement elem = this.ParentElement;
if (elem != null) {
- return elem.ResolvePrefix(this.Prefix);
+ return elem.LookupNamespace(this.Prefix) ?? NoNamespace;
}
return NoNamespace; // Orphaned attribute
}
diff --git a/ICSharpCode.NRefactory.Xml/AXmlDocument.cs b/ICSharpCode.NRefactory.Xml/AXmlDocument.cs
index 66a97957..165c67e0 100644
--- a/ICSharpCode.NRefactory.Xml/AXmlDocument.cs
+++ b/ICSharpCode.NRefactory.Xml/AXmlDocument.cs
@@ -19,6 +19,7 @@
using System;
using System.Globalization;
using System.Xml;
+using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.NRefactory.Xml
{
@@ -32,16 +33,9 @@ namespace ICSharpCode.NRefactory.Xml
{
}
- /// <inheritdoc/>
- public override XmlReader CreateReader()
- {
- return new AXmlReader(internalObject.NestedObjects);
- }
-
- /// <inheritdoc/>
- public override XmlReader CreateReader(Func<int, TextLocation> offsetToTextLocation)
+ internal override ObjectIterator CreateIteratorForReader()
{
- return new AXmlReader(internalObject.NestedObjects, startOffset, offsetToTextLocation);
+ return new ObjectIterator(internalObject.NestedObjects, startOffset);
}
/// <inheritdoc/>
diff --git a/ICSharpCode.NRefactory.Xml/AXmlElement.cs b/ICSharpCode.NRefactory.Xml/AXmlElement.cs
index c5efae36..e4ed76ea 100644
--- a/ICSharpCode.NRefactory.Xml/AXmlElement.cs
+++ b/ICSharpCode.NRefactory.Xml/AXmlElement.cs
@@ -20,13 +20,14 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using System.Xml;
namespace ICSharpCode.NRefactory.Xml
{
/// <summary>
/// XML element.
/// </summary>
- public class AXmlElement : AXmlObject
+ public class AXmlElement : AXmlObject, IXmlNamespaceResolver
{
internal AXmlElement(AXmlObject parent, int startOffset, InternalElement internalObject)
: base(parent, startOffset, internalObject)
@@ -90,7 +91,7 @@ namespace ICSharpCode.NRefactory.Xml
/// <summary> The part of name before ":" </summary>
/// <returns> Empty string if not found </returns>
public string Prefix {
- get { return ((InternalElement)internalObject).Prefix; }
+ get { return ((InternalElement)internalObject).Prefix; }
}
/// <summary> The part of name after ":" </summary>
@@ -104,26 +105,37 @@ namespace ICSharpCode.NRefactory.Xml
public string Namespace {
get {
string prefix = this.Prefix;
- return ResolvePrefix(prefix);
+ return LookupNamespace(prefix);
}
}
- /// <summary> Find the defualt namespace for this context </summary>
+ /// <summary> Find the default namespace for this context </summary>
+ [Obsolete("Use LookupNamespace(string.Empty) instead")]
public string FindDefaultNamespace()
{
- return ResolvePrefix(string.Empty);
+ return LookupNamespace(string.Empty) ?? NoNamespace;
}
/// <summary>
/// Recursively resolve given prefix in this context. Prefix must have some value.
/// </summary>
/// <returns> Empty string if prefix is not found </returns>
+ [Obsolete("Use LookupNamespace() instead")]
public string ResolvePrefix(string prefix)
{
+ return LookupNamespace(prefix) ?? NoNamespace;
+ }
+
+ /// <summary>
+ /// Recursively resolve given prefix in this context.
+ /// </summary>
+ /// <returns><c>null</c> if prefix is not found</returns>
+ public string LookupNamespace(string prefix)
+ {
if (prefix == null)
throw new ArgumentNullException("prefix");
- // Implicit namesapces
+ // Implicit namespaces
if (prefix == "xml") return XmlNamespace;
if (prefix == "xmlns") return XmlnsNamespace;
@@ -134,7 +146,60 @@ namespace ICSharpCode.NRefactory.Xml
return attr.Value;
}
}
- return NoNamespace; // Can not find prefix
+ return null; // Can not find prefix
+ }
+
+ /// <summary>
+ /// Gets the prefix that is mapped to the specified namespace URI.
+ /// </summary>
+ /// <returns>The prefix that is mapped to the namespace URI; null if the namespace URI is not mapped to a prefix.</returns>
+ public string LookupPrefix(string namespaceName)
+ {
+ if (namespaceName == null)
+ throw new ArgumentNullException("namespaceName");
+
+ if (namespaceName == XmlNamespace)
+ return "xml";
+ if (namespaceName == XmlnsNamespace)
+ return "xmlns";
+ for (AXmlElement current = this; current != null; current = current.Parent as AXmlElement) {
+ foreach (var attr in current.Attributes) {
+ if (attr.Value == namespaceName) {
+ if (attr.Name.StartsWith("xmlns:", StringComparison.Ordinal))
+ return attr.LocalName;
+ else if (attr.Name == "xmlns")
+ return string.Empty;
+ }
+ }
+ }
+ return null; // Can not find prefix
+ }
+
+ /// <summary>
+ /// Gets a collection of defined prefix-namespace mappings that are currently in scope.
+ /// </summary>
+ public IDictionary<string, string> GetNamespacesInScope(XmlNamespaceScope scope)
+ {
+ var result = new Dictionary<string, string>();
+ if (scope == XmlNamespaceScope.All) {
+ result["xml"] = XmlNamespace;
+ result["xmlns"] = XmlnsNamespace;
+ }
+ for (AXmlElement current = this; current != null; current = current.Parent as AXmlElement) {
+ foreach (var attr in current.Attributes) {
+ if (attr.Name.StartsWith("xmlns:", StringComparison.Ordinal)) {
+ string prefix = attr.LocalName;
+ if (!result.ContainsKey(prefix)) {
+ result.Add(prefix, attr.Value);
+ }
+ } else if (attr.Name == "xmlns" && !result.ContainsKey(string.Empty)) {
+ result.Add(string.Empty, attr.Value);
+ }
+ }
+ if (scope == XmlNamespaceScope.Local)
+ break;
+ }
+ return result;
}
/// <summary>
@@ -144,7 +209,7 @@ namespace ICSharpCode.NRefactory.Xml
/// <returns>Null if not found</returns>
public string GetAttributeValue(string localName)
{
- return GetAttributeValue(NoNamespace, localName);
+ return GetAttributeValue(string.Empty, localName);
}
/// <summary>
diff --git a/ICSharpCode.NRefactory.Xml/AXmlObject.cs b/ICSharpCode.NRefactory.Xml/AXmlObject.cs
index 269a54da..c139efd3 100644
--- a/ICSharpCode.NRefactory.Xml/AXmlObject.cs
+++ b/ICSharpCode.NRefactory.Xml/AXmlObject.cs
@@ -31,7 +31,7 @@ namespace ICSharpCode.NRefactory.Xml
public abstract class AXmlObject : ISegment
{
/// <summary> Empty string. The namespace used if there is no "xmlns" specified </summary>
- public static readonly string NoNamespace = string.Empty;
+ internal static readonly string NoNamespace = string.Empty;
/// <summary> Namespace for "xml:" prefix: "http://www.w3.org/XML/1998/namespace" </summary>
public static readonly string XmlNamespace = "http://www.w3.org/XML/1998/namespace";
@@ -54,17 +54,58 @@ namespace ICSharpCode.NRefactory.Xml
/// <summary>
/// Creates an XML reader that reads from this document.
/// </summary>
- public virtual XmlReader CreateReader()
+ /// <remarks>
+ /// The reader will ignore comments and processing instructions; and will not have line information.
+ /// </remarks>
+ public XmlReader CreateReader()
{
- return new AXmlReader(new[] { internalObject });
+ return new AXmlReader(CreateIteratorForReader());
}
/// <summary>
/// Creates an XML reader that reads from this document.
/// </summary>
- public virtual XmlReader CreateReader(Func<int, TextLocation> offsetToTextLocation)
+ /// <param name="settings">Reader settings.
+ /// Currently, only <c>IgnoreComments</c> is supported.</param>
+ /// <remarks>
+ /// The reader will not have line information.
+ /// </remarks>
+ public XmlReader CreateReader(XmlReaderSettings settings)
{
- return new AXmlReader(new[] { internalObject }, startOffset, offsetToTextLocation);
+ return new AXmlReader(CreateIteratorForReader(), settings);
+ }
+
+ /// <summary>
+ /// Creates an XML reader that reads from this document.
+ /// </summary>
+ /// <param name="settings">Reader settings.
+ /// Currently, only <c>IgnoreComments</c> is supported.</param>
+ /// <param name="document">
+ /// The document that was used to parse the XML. It is used to convert offsets to line information.
+ /// </param>
+ public XmlReader CreateReader(XmlReaderSettings settings, IDocument document)
+ {
+ if (document == null)
+ throw new ArgumentNullException("document");
+ return new AXmlReader(CreateIteratorForReader(), settings, document.GetLocation);
+ }
+
+ /// <summary>
+ /// Creates an XML reader that reads from this document.
+ /// </summary>
+ /// <param name="settings">Reader settings.
+ /// Currently, only <c>IgnoreComments</c> is supported.</param>
+ /// <param name="offsetToTextLocation">
+ /// A function for converting offsets to line information.
+ /// </param>
+ public XmlReader CreateReader(XmlReaderSettings settings, Func<int, TextLocation> offsetToTextLocation)
+ {
+ return new AXmlReader(CreateIteratorForReader(), settings, offsetToTextLocation);
+ }
+
+ internal virtual ObjectIterator CreateIteratorForReader()
+ {
+ return new ObjectIterator(new[] { internalObject }, startOffset);
}
/// <summary>
@@ -100,7 +141,7 @@ namespace ICSharpCode.NRefactory.Xml
/// <summary>
/// Gets a child fully containg the given offset.
/// Goes recursively down the tree.
- /// Specail case if at the end of attribute or text
+ /// Special case if at the end of attribute or text
/// </summary>
public AXmlObject GetChildAtOffset(int offset)
{
diff --git a/ICSharpCode.NRefactory.Xml/AXmlReader.cs b/ICSharpCode.NRefactory.Xml/AXmlReader.cs
index ae503861..48cd32ee 100644
--- a/ICSharpCode.NRefactory.Xml/AXmlReader.cs
+++ b/ICSharpCode.NRefactory.Xml/AXmlReader.cs
@@ -20,6 +20,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
+using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.NRefactory.Xml
{
@@ -29,18 +30,21 @@ namespace ICSharpCode.NRefactory.Xml
sealed class AXmlReader : XmlReader, IXmlLineInfo
{
readonly ObjectIterator objectIterator;
- readonly Func<int, TextLocation> offsetToTextLocation;
- readonly XmlNameTable nameTable = new NameTable();
+ readonly XmlReaderSettings settings;
+ Func<int, TextLocation> offsetToTextLocation;
+ readonly XmlNameTable nameTable;
ReadState readState = ReadState.Initial;
XmlNodeType elementNodeType = XmlNodeType.None;
IList<InternalAttribute> attributes;
int attributeIndex = -1;
bool inAttributeValue;
- internal AXmlReader(InternalObject[] objects, int startPosition = 0, Func<int, TextLocation> offsetToTextLocation = null)
+ internal AXmlReader(ObjectIterator objectIterator, XmlReaderSettings settings = null, Func<int, TextLocation> offsetToTextLocation = null)
{
+ this.objectIterator = objectIterator;
+ this.settings = settings ?? new XmlReaderSettings();
this.offsetToTextLocation = offsetToTextLocation;
- objectIterator = new ObjectIterator(objects, startPosition);
+ this.nameTable = this.settings.NameTable ?? new NameTable();
objectIterator.StopAtElementEnd = true;
}
@@ -53,6 +57,10 @@ namespace ICSharpCode.NRefactory.Xml
get { return readState; }
}
+ public override XmlReaderSettings Settings {
+ get { return settings; }
+ }
+
public override bool ReadAttributeValue()
{
if (attributeIndex >= 0 && !inAttributeValue) {
@@ -88,8 +96,11 @@ namespace ICSharpCode.NRefactory.Xml
elementNodeType = XmlNodeType.None;
return false;
} else if (objectIterator.IsAtElementEnd) {
- elementNodeType = XmlNodeType.EndElement;
- return true;
+ // Don't report EndElement for empty elements
+ if (!IsEmptyElement) {
+ elementNodeType = XmlNodeType.EndElement;
+ return true;
+ }
} else if (obj is InternalElement) {
// element start
elementNodeType = XmlNodeType.Element;
@@ -106,8 +117,15 @@ namespace ICSharpCode.NRefactory.Xml
}
return true;
} else if (obj is InternalTag) {
- // start/end tags can be skipped as the parent InternalElement already handles them,
- // TODO all other tags (xml decl, comments, ...)
+ InternalTag tag = (InternalTag)obj;
+ if (tag.IsStartOrEmptyTag || tag.IsEndTag) {
+ // start/end tags can be skipped as the parent InternalElement already handles them
+ } else if (tag.IsComment && !settings.IgnoreComments) {
+ elementNodeType = XmlNodeType.Comment;
+ return true;
+ } else {
+ // TODO all other tags
+ }
} else {
throw new NotSupportedException();
}
@@ -175,7 +193,10 @@ namespace ICSharpCode.NRefactory.Xml
return string.Empty;
if (attributeIndex >= 0)
return attributes[attributeIndex].Value;
- InternalText text = objectIterator.CurrentObject as InternalText;
+ InternalObject currentObject = objectIterator.CurrentObject;
+ InternalText text = currentObject as InternalText;
+ if (text == null && currentObject is InternalTag && currentObject.NestedObjects.Length == 1)
+ text = currentObject.NestedObjects[0] as InternalText;
return text != null ? text.Value : string.Empty;
}
}
@@ -300,6 +321,7 @@ namespace ICSharpCode.NRefactory.Xml
public override void Close()
{
readState = ReadState.Closed;
+ offsetToTextLocation = null;
}
public override string BaseURI {
diff --git a/ICSharpCode.NRefactory.Xml/TagReader.cs b/ICSharpCode.NRefactory.Xml/TagReader.cs
index 49423307..e5cab934 100644
--- a/ICSharpCode.NRefactory.Xml/TagReader.cs
+++ b/ICSharpCode.NRefactory.Xml/TagReader.cs
@@ -152,7 +152,7 @@ namespace ICSharpCode.NRefactory.Xml
});
} else {
// Mismatched name - the nesting isn't properly;
- // clear the whole stack so that none of the currently open elements are closed as property-nested.
+ // clear the whole stack so that none of the currently open elements are closed as properly-nested.
elementNameStack.Clear();
}
}