Browse Source

AXmlReader: Fix handling of XML namespaces and CDATA.

pull/32/merge
Daniel Grunwald 12 years ago
parent
commit
fac34c27cd
  1. 17
      ICSharpCode.NRefactory.ConsistencyCheck/Xml/XmlReaderTest.cs
  2. 2
      ICSharpCode.NRefactory.Xml/AXmlElement.cs
  3. 143
      ICSharpCode.NRefactory.Xml/AXmlReader.cs

17
ICSharpCode.NRefactory.ConsistencyCheck/Xml/XmlReaderTest.cs

@ -34,15 +34,16 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck.Xml
{ {
public static void Run(string fileName) public static void Run(string fileName)
{ {
bool includeAttributes = true;
var textSource = new StringTextSource(File.ReadAllText(fileName)); var textSource = new StringTextSource(File.ReadAllText(fileName));
using (var textReader = textSource.CreateReader()) { using (var textReader = textSource.CreateReader()) {
using (var xmlReader = new XmlTextReader(textReader)) { using (var xmlReader = new XmlTextReader(textReader)) {
Run(xmlReader); Run(xmlReader, includeAttributes);
} }
} }
var doc = new AXmlParser().Parse(textSource); var doc = new AXmlParser().Parse(textSource);
using (var xmlReader = doc.CreateReader()) { using (var xmlReader = doc.CreateReader()) {
Run(xmlReader); Run(xmlReader, includeAttributes);
} }
var xmlDocument = new XmlDocument(); var xmlDocument = new XmlDocument();
xmlDocument.Load(doc.CreateReader()); xmlDocument.Load(doc.CreateReader());
@ -62,7 +63,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck.Xml
"SchemaInfo", "BaseURI", "Settings" "SchemaInfo", "BaseURI", "Settings"
}; };
public static void Run(XmlReader reader) public static void Run(XmlReader reader, bool includeAttributes, bool includeAttributeValues = true)
{ {
using (StreamWriter output = File.CreateText(Path.Combine(Program.TempPath, reader.GetType().Name + "-output.csv"))) { using (StreamWriter output = File.CreateText(Path.Combine(Program.TempPath, reader.GetType().Name + "-output.csv"))) {
var properties = typeof(XmlReader).GetProperties(BindingFlags.Public | BindingFlags.Instance) var properties = typeof(XmlReader).GetProperties(BindingFlags.Public | BindingFlags.Instance)
@ -71,6 +72,16 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck.Xml
output.WriteLine(CSV(properties.Select(p => p.Name))); output.WriteLine(CSV(properties.Select(p => p.Name)));
do { do {
output.WriteLine(CSV(properties.Select(p => ToString(p.GetValue(reader, null))))); output.WriteLine(CSV(properties.Select(p => ToString(p.GetValue(reader, null)))));
if (includeAttributes && reader.HasAttributes) {
for (int i = 0; i < reader.AttributeCount; i++) {
reader.MoveToAttribute(i);
output.WriteLine(CSV(properties.Select(p => ToString(p.GetValue(reader, null)))));
if (includeAttributeValues) {
reader.ReadAttributeValue();
output.WriteLine(CSV(properties.Select(p => ToString(p.GetValue(reader, null)))));
}
}
}
} while (reader.Read()); } while (reader.Read());
output.WriteLine(CSV(properties.Select(p => ToString(p.GetValue(reader, null))))); output.WriteLine(CSV(properties.Select(p => ToString(p.GetValue(reader, null)))));
} }

2
ICSharpCode.NRefactory.Xml/AXmlElement.cs

@ -183,7 +183,7 @@ namespace ICSharpCode.NRefactory.Xml
var result = new Dictionary<string, string>(); var result = new Dictionary<string, string>();
if (scope == XmlNamespaceScope.All) { if (scope == XmlNamespaceScope.All) {
result["xml"] = XmlNamespace; result["xml"] = XmlNamespace;
result["xmlns"] = XmlnsNamespace; //result["xmlns"] = XmlnsNamespace; xmlns should not be included in GetNamespacesInScope() results
} }
for (AXmlElement current = this; current != null; current = current.Parent as AXmlElement) { for (AXmlElement current = this; current != null; current = current.Parent as AXmlElement) {
foreach (var attr in current.Attributes) { foreach (var attr in current.Attributes) {

143
ICSharpCode.NRefactory.Xml/AXmlReader.cs

@ -19,6 +19,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Xml; using System.Xml;
using ICSharpCode.NRefactory.Editor; using ICSharpCode.NRefactory.Editor;
@ -33,6 +34,7 @@ namespace ICSharpCode.NRefactory.Xml
readonly XmlReaderSettings settings; readonly XmlReaderSettings settings;
Func<int, TextLocation> offsetToTextLocation; Func<int, TextLocation> offsetToTextLocation;
readonly XmlNameTable nameTable; readonly XmlNameTable nameTable;
readonly XmlNamespaceManager nsManager;
ReadState readState = ReadState.Initial; ReadState readState = ReadState.Initial;
XmlNodeType elementNodeType = XmlNodeType.None; XmlNodeType elementNodeType = XmlNodeType.None;
IList<InternalAttribute> attributes; IList<InternalAttribute> attributes;
@ -45,6 +47,7 @@ namespace ICSharpCode.NRefactory.Xml
this.settings = settings ?? new XmlReaderSettings(); this.settings = settings ?? new XmlReaderSettings();
this.offsetToTextLocation = offsetToTextLocation; this.offsetToTextLocation = offsetToTextLocation;
this.nameTable = this.settings.NameTable ?? new NameTable(); this.nameTable = this.settings.NameTable ?? new NameTable();
this.nsManager = new XmlNamespaceManager(this.nameTable);
objectIterator.StopAtElementEnd = true; objectIterator.StopAtElementEnd = true;
} }
@ -77,6 +80,7 @@ namespace ICSharpCode.NRefactory.Xml
readState = ReadState.Interactive; readState = ReadState.Interactive;
return ReadCurrentPosition(); return ReadCurrentPosition();
case ReadState.Interactive: case ReadState.Interactive:
LeaveNode();
objectIterator.MoveInto(); objectIterator.MoveInto();
return ReadCurrentPosition(); return ReadCurrentPosition();
default: default:
@ -96,8 +100,10 @@ namespace ICSharpCode.NRefactory.Xml
elementNodeType = XmlNodeType.None; elementNodeType = XmlNodeType.None;
return false; return false;
} else if (objectIterator.IsAtElementEnd) { } else if (objectIterator.IsAtElementEnd) {
// Don't report EndElement for empty elements if (IsEmptyElement) {
if (!IsEmptyElement) { // Don't report EndElement for empty elements
nsManager.PopScope();
} else {
elementNodeType = XmlNodeType.EndElement; elementNodeType = XmlNodeType.EndElement;
return true; return true;
} }
@ -105,8 +111,17 @@ namespace ICSharpCode.NRefactory.Xml
// element start // element start
elementNodeType = XmlNodeType.Element; elementNodeType = XmlNodeType.Element;
InternalTag startTag = ((InternalTag)obj.NestedObjects[0]); InternalTag startTag = ((InternalTag)obj.NestedObjects[0]);
if (startTag.NestedObjects != null) nsManager.PushScope();
if (startTag.NestedObjects != null) {
attributes = startTag.NestedObjects.OfType<InternalAttribute>().ToList(); attributes = startTag.NestedObjects.OfType<InternalAttribute>().ToList();
for (int i = 0; i < attributes.Count; i++) {
var attr = attributes[i];
if (attr.Name.StartsWith("xmlns:", StringComparison.Ordinal))
nsManager.AddNamespace(AXmlObject.GetLocalName(attr.Name), attr.Value);
else if (attr.Name == "xmlns")
nsManager.AddNamespace(string.Empty, attr.Value);
}
}
return true; return true;
} else if (obj is InternalText) { } else if (obj is InternalText) {
InternalText text = (InternalText)obj; InternalText text = (InternalText)obj;
@ -123,6 +138,17 @@ namespace ICSharpCode.NRefactory.Xml
} else if (tag.IsComment && !settings.IgnoreComments) { } else if (tag.IsComment && !settings.IgnoreComments) {
elementNodeType = XmlNodeType.Comment; elementNodeType = XmlNodeType.Comment;
return true; return true;
} else if (tag.IsProcessingInstruction && !settings.IgnoreProcessingInstructions) {
if (tag.Name == "xml") {
elementNodeType = XmlNodeType.XmlDeclaration;
attributes = tag.NestedObjects.OfType<InternalAttribute>().ToList();
} else {
elementNodeType = XmlNodeType.ProcessingInstruction;
}
return true;
} else if (tag.IsCData) {
elementNodeType = XmlNodeType.CDATA;
return true;
} else { } else {
// TODO all other tags // TODO all other tags
} }
@ -133,10 +159,18 @@ namespace ICSharpCode.NRefactory.Xml
} }
} }
void LeaveNode()
{
if (elementNodeType == XmlNodeType.EndElement) {
nsManager.PopScope();
}
}
public override void Skip() public override void Skip()
{ {
if (readState == ReadState.Interactive) { if (readState == ReadState.Interactive) {
MoveToElement(); MoveToElement();
LeaveNode();
objectIterator.MoveNext(); objectIterator.MoveNext();
ReadCurrentPosition(); ReadCurrentPosition();
} }
@ -160,7 +194,9 @@ namespace ICSharpCode.NRefactory.Xml
get { get {
if (readState != ReadState.Interactive) if (readState != ReadState.Interactive)
return string.Empty; return string.Empty;
return LookupNamespace(this.Prefix); if (attributeIndex >= 0 && !inAttributeValue && attributes[attributeIndex].Name == "xmlns")
return AXmlObject.XmlnsNamespace;
return LookupNamespace(this.Prefix) ?? string.Empty;
} }
} }
@ -173,14 +209,50 @@ namespace ICSharpCode.NRefactory.Xml
return string.Empty; return string.Empty;
return nameTable.Add(AXmlObject.GetLocalName(attributes[attributeIndex].Name)); return nameTable.Add(AXmlObject.GetLocalName(attributes[attributeIndex].Name));
} }
InternalElement element = objectIterator.CurrentObject as InternalElement; string result;
return element != null ? nameTable.Add(element.LocalName) : string.Empty; switch (elementNodeType) {
case XmlNodeType.Element:
case XmlNodeType.EndElement:
result = ((InternalElement)objectIterator.CurrentObject).LocalName;
break;
case XmlNodeType.XmlDeclaration:
result = "xml";
break;
default:
return string.Empty;
}
return nameTable.Add(result);
} }
} }
public override bool IsEmptyElement { public override string Name {
get { get {
if (readState != ReadState.Interactive) if (readState != ReadState.Interactive)
return string.Empty;
if (attributeIndex >= 0) {
if (inAttributeValue)
return string.Empty;
return nameTable.Add(attributes[attributeIndex].Name);
}
string result;
switch (elementNodeType) {
case XmlNodeType.Element:
case XmlNodeType.EndElement:
result = ((InternalElement)objectIterator.CurrentObject).Name;
break;
case XmlNodeType.XmlDeclaration:
result = "xml";
break;
default:
return string.Empty;
}
return nameTable.Add(result);
}
}
public override bool IsEmptyElement {
get {
if (readState != ReadState.Interactive || attributeIndex >= 0)
return false; return false;
InternalElement element = objectIterator.CurrentObject as InternalElement; InternalElement element = objectIterator.CurrentObject as InternalElement;
return element != null && element.NestedObjects.Length == 1; return element != null && element.NestedObjects.Length == 1;
@ -193,17 +265,51 @@ namespace ICSharpCode.NRefactory.Xml
return string.Empty; return string.Empty;
if (attributeIndex >= 0) if (attributeIndex >= 0)
return attributes[attributeIndex].Value; return attributes[attributeIndex].Value;
InternalObject currentObject = objectIterator.CurrentObject; switch (elementNodeType) {
InternalText text = currentObject as InternalText; case XmlNodeType.Text:
if (text == null && currentObject is InternalTag && currentObject.NestedObjects.Length == 1) case XmlNodeType.Whitespace:
text = currentObject.NestedObjects[0] as InternalText; return ((InternalText)objectIterator.CurrentObject).Value;
return text != null ? text.Value : string.Empty; case XmlNodeType.Comment:
case XmlNodeType.CDATA:
var nestedObjects = objectIterator.CurrentObject.NestedObjects;
if (nestedObjects.Length == 1)
return ((InternalText)nestedObjects[0]).Value;
else
return string.Empty;
case XmlNodeType.XmlDeclaration:
StringBuilder b = new StringBuilder();
foreach (var attr in objectIterator.CurrentObject.NestedObjects.OfType<InternalAttribute>()) {
if (b.Length > 0)
b.Append(' ');
b.Append(attr.Name);
b.Append('=');
b.Append('"');
b.Append(attr.Value);
b.Append('"');
}
return b.ToString();
default:
return string.Empty;
}
} }
} }
public override bool HasValue { public override bool HasValue {
get { get {
return !string.IsNullOrEmpty (Value); if (readState != ReadState.Interactive)
return false;
if (attributeIndex >= 0)
return true;
switch (elementNodeType) {
case XmlNodeType.Text:
case XmlNodeType.Whitespace:
case XmlNodeType.Comment:
case XmlNodeType.XmlDeclaration:
case XmlNodeType.CDATA:
return true;
default:
return false;
}
} }
} }
@ -272,7 +378,7 @@ namespace ICSharpCode.NRefactory.Xml
if (attributes == null) if (attributes == null)
return -1; return -1;
for (int i = 0; i < attributes.Count; i++) { for (int i = 0; i < attributes.Count; i++) {
if (AXmlObject.GetLocalName(attributes[i].Name) == name && LookupNamespace(AXmlObject.GetNamespacePrefix(attributes[i].Name)) == ns) if (AXmlObject.GetLocalName(attributes[i].Name) == name && (LookupNamespace(AXmlObject.GetNamespacePrefix(attributes[i].Name)) ?? string.Empty) == ns)
return i; return i;
} }
return -1; return -1;
@ -290,7 +396,7 @@ namespace ICSharpCode.NRefactory.Xml
public override string LookupNamespace(string prefix) public override string LookupNamespace(string prefix)
{ {
return string.Empty; // TODO implement namespace lookup return nsManager.LookupNamespace(prefix);
} }
public override string GetAttribute(int i) public override string GetAttribute(int i)
@ -315,7 +421,12 @@ namespace ICSharpCode.NRefactory.Xml
} }
public override int Depth { public override int Depth {
get { return objectIterator.Depth; } get {
if (attributeIndex < 0)
return objectIterator.Depth;
else
return objectIterator.Depth + (inAttributeValue ? 2 : 1);
}
} }
public override void Close() public override void Close()

Loading…
Cancel
Save