Browse Source

XML Parser: Fixed some bugs. Hereby declaring code ready for use.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4717 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 17 years ago
parent
commit
551566b0c7
  1. 8
      samples/XmlDOM/Window1.xaml.cs
  2. 12
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlContainer.cs
  3. 10
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlParser.cs
  4. 4
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/TagMatchingHeuristics.cs
  5. 21
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/TrackedSegmentCollection.cs

8
samples/XmlDOM/Window1.xaml.cs

@ -72,7 +72,13 @@ namespace XmlDOM
void Button_Click(object sender, RoutedEventArgs e) void Button_Click(object sender, RoutedEventArgs e)
{ {
if (!textDirty) return; if (!textDirty) return;
AXmlDocument doc = parser.Parse(); AXmlDocument doc;
parser.Lock.EnterWriteLock();
try {
doc = parser.Parse();
} finally {
parser.Lock.ExitWriteLock();
}
if (treeView.Items.Count == 0) { if (treeView.Items.Count == 0) {
treeView.Items.Add(doc); treeView.Items.Add(doc);
} }

12
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlContainer.cs

@ -155,7 +155,6 @@ namespace ICSharpCode.AvalonEdit.Xml
// item.DebugCheckConsistency(false); // item.DebugCheckConsistency(false);
// The parent (or any futher parents) can not be part of parsed document // The parent (or any futher parents) can not be part of parsed document
// becuase otherwise this item would be included twice => safe to change parents // becuase otherwise this item would be included twice => safe to change parents
DebugAssert(item.Parent.Document == null, "Old parent is part of document as well");
// Maintain cache constraint by setting parents to null // Maintain cache constraint by setting parents to null
foreach(AXmlObject ancest in item.GetAncestors().ToList()) { foreach(AXmlObject ancest in item.GetAncestors().ToList()) {
ancest.Parent = null; ancest.Parent = null;
@ -205,9 +204,9 @@ namespace ICSharpCode.AvalonEdit.Xml
Assert(child.Document != null, "Child has null document"); Assert(child.Document != null, "Child has null document");
Assert(child.Document == this.Document, "Child is in different document"); Assert(child.Document == this.Document, "Child is in different document");
} }
Assert(myStartOffset <= child.StartOffset && child.EndOffset <= myEndOffset, "Child not within parent text range");
if (this.IsCached) if (this.IsCached)
Assert(child.IsCached, "Child not in cache"); Assert(child.IsCached, "Child not in cache");
Assert(myStartOffset <= child.StartOffset && child.EndOffset <= myEndOffset, "Child not within parent text range");
if (prevChild != null) if (prevChild != null)
Assert(prevChild.EndOffset <= child.StartOffset, "Overlaping childs"); Assert(prevChild.EndOffset <= child.StartOffset, "Overlaping childs");
child.DebugCheckConsistency(checkParentPointers); child.DebugCheckConsistency(checkParentPointers);
@ -221,6 +220,7 @@ namespace ICSharpCode.AvalonEdit.Xml
/// </remarks> /// </remarks>
internal void UpdateTreeFrom(AXmlContainer srcContainer) internal void UpdateTreeFrom(AXmlContainer srcContainer)
{ {
this.StartOffset = srcContainer.StartOffset; // Force the update
this.UpdateDataFrom(srcContainer); this.UpdateDataFrom(srcContainer);
RemoveChildrenNotIn(srcContainer.Children); RemoveChildrenNotIn(srcContainer.Children);
InsertAndUpdateChildrenFrom(srcContainer.Children); InsertAndUpdateChildrenFrom(srcContainer.Children);
@ -236,7 +236,8 @@ namespace ICSharpCode.AvalonEdit.Xml
if (srcChildren.TryGetValue(child.StartOffset, out srcChild) && child.CanUpdateDataFrom(srcChild)) { if (srcChildren.TryGetValue(child.StartOffset, out srcChild) && child.CanUpdateDataFrom(srcChild)) {
// Keep only one item with given offset (we might have several due to deletion) // Keep only one item with given offset (we might have several due to deletion)
srcChildren.Remove(child.StartOffset); srcChildren.Remove(child.StartOffset);
if (child is AXmlContainer) // If contaner that needs updating
if (child is AXmlContainer && child.LastUpdatedFrom != srcChild)
((AXmlContainer)child).RemoveChildrenNotIn(((AXmlContainer)srcChild).Children); ((AXmlContainer)child).RemoveChildrenNotIn(((AXmlContainer)srcChild).Children);
i++; i++;
} else { } else {
@ -256,10 +257,13 @@ namespace ICSharpCode.AvalonEdit.Xml
AXmlObject child = this.Children[i]; AXmlObject child = this.Children[i];
AXmlObject srcChild = srcList[i]; AXmlObject srcChild = srcList[i];
if (child.CanUpdateDataFrom(srcChild) /* includes offset test */) { if (child.CanUpdateDataFrom(srcChild)) { // includes offset test
// Does it need updating?
if (child.LastUpdatedFrom != srcChild) {
child.UpdateDataFrom(srcChild); child.UpdateDataFrom(srcChild);
if (child is AXmlContainer) if (child is AXmlContainer)
((AXmlContainer)child).InsertAndUpdateChildrenFrom(((AXmlContainer)srcChild).Children); ((AXmlContainer)child).InsertAndUpdateChildrenFrom(((AXmlContainer)srcChild).Children);
}
} else { } else {
InsertChild(i, srcChild); InsertChild(i, srcChild);
} }

10
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/AXmlParser.cs

@ -105,11 +105,15 @@ namespace ICSharpCode.AvalonEdit.Xml
public AXmlParser(string input) public AXmlParser(string input)
{ {
this.input = input; this.input = input;
this.userDocument = new AXmlDocument() { Parser = this };
this.userDocument.Document = this.userDocument;
this.UknonwEntityReferenceIsError = true; this.UknonwEntityReferenceIsError = true;
this.TrackedSegments = new TrackedSegmentCollection(); this.TrackedSegments = new TrackedSegmentCollection();
this.lockObject = new ReaderWriterLockSlim(); this.lockObject = new ReaderWriterLockSlim();
this.userDocument = new AXmlDocument() { Parser = this };
this.userDocument.Document = this.userDocument;
// Track the document
this.TrackedSegments.AddParsedObject(this.userDocument, null);
this.userDocument.IsCached = false;
} }
/// <summary> /// <summary>
@ -165,11 +169,11 @@ namespace ICSharpCode.AvalonEdit.Xml
TagReader tagReader = new TagReader(this, input); TagReader tagReader = new TagReader(this, input);
List<AXmlObject> tags = tagReader.ReadAllTags(); List<AXmlObject> tags = tagReader.ReadAllTags();
AXmlDocument parsedDocument = new TagMatchingHeuristics(this, input, tags).ReadDocument(); AXmlDocument parsedDocument = new TagMatchingHeuristics(this, input, tags).ReadDocument();
// parsedDocument.DebugCheckConsistency(false);
tagReader.PrintStringCacheStats(); tagReader.PrintStringCacheStats();
AXmlParser.Log("Updating main DOM tree..."); AXmlParser.Log("Updating main DOM tree...");
userDocument.UpdateTreeFrom(parsedDocument); userDocument.UpdateTreeFrom(parsedDocument);
userDocument.DebugCheckConsistency(true); userDocument.DebugCheckConsistency(true);
Assert(userDocument.GetSelfAndAllChildren().Count() == parsedDocument.GetSelfAndAllChildren().Count(), "Parsed document and updated document have different number of children");
return userDocument; return userDocument;
} }

4
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/TagMatchingHeuristics.cs

@ -35,9 +35,9 @@ namespace ICSharpCode.AvalonEdit.Xml
{ {
AXmlDocument doc = new AXmlDocument() { Parser = parser }; AXmlDocument doc = new AXmlDocument() { Parser = parser };
AXmlParser.Log("Flat stream: {0}", PrintObjects(tags)); // AXmlParser.Log("Flat stream: {0}", PrintObjects(tags));
List<AXmlObject> valid = MatchTags(tags); List<AXmlObject> valid = MatchTags(tags);
AXmlParser.Log("Fixed stream: {0}", PrintObjects(valid)); // AXmlParser.Log("Fixed stream: {0}", PrintObjects(valid));
IEnumerator<AXmlObject> validStream = valid.GetEnumerator(); IEnumerator<AXmlObject> validStream = valid.GetEnumerator();
validStream.MoveNext(); // Move to first validStream.MoveNext(); // Move to first
while(true) { while(true) {

21
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/TrackedSegmentCollection.cs

@ -58,7 +58,7 @@ namespace ICSharpCode.AvalonEdit.Xml
public void AddParsedObject(AXmlObject obj, int? maxTouchedLocation) public void AddParsedObject(AXmlObject obj, int? maxTouchedLocation)
{ {
AXmlParser.Assert(obj.Length > 0 || obj is AXmlDocument, string.Format("Invalid object {0}. It has zero length.", obj)); AXmlParser.Assert(obj.Length > 0 || obj is AXmlDocument, string.Format("Invalid object {0}. It has zero length.", obj));
// Expensive check // // Expensive check
// if (obj is AXmlContainer) { // if (obj is AXmlContainer) {
// int objStartOffset = obj.StartOffset; // int objStartOffset = obj.StartOffset;
// int objEndOffset = obj.EndOffset; // int objEndOffset = obj.EndOffset;
@ -82,13 +82,19 @@ namespace ICSharpCode.AvalonEdit.Xml
} }
} }
/// <summary> Removes object with all of its children </summary> /// <summary> Removes object with all of its non-cached children </summary>
public void RemoveParsedObject(AXmlObject obj) public void RemoveParsedObject(AXmlObject obj)
{ {
foreach(AXmlObject child in obj.GetSelfAndAllChildren()) { // Cached objects may be used in the future - do not remove them
bool found = segments.Remove(child); if (obj.IsCached) return;
AXmlParser.DebugAssert(found, string.Format("{0} not found", child)); segments.Remove(obj);
RemoveSyntaxErrorsOf(child); RemoveSyntaxErrorsOf(obj);
AXmlParser.Log("Stopped tracking {0}", obj);
if (obj is AXmlContainer) {
foreach(AXmlObject child in ((AXmlContainer)obj).Children) {
RemoveParsedObject(child);
}
} }
} }
@ -102,8 +108,7 @@ namespace ICSharpCode.AvalonEdit.Xml
public void RemoveSyntaxErrorsOf(AXmlObject obj) public void RemoveSyntaxErrorsOf(AXmlObject obj)
{ {
foreach(SyntaxError syntaxError in obj.MySyntaxErrors) { foreach(SyntaxError syntaxError in obj.MySyntaxErrors) {
bool found = segments.Remove(syntaxError); segments.Remove(syntaxError);
AXmlParser.DebugAssert(found, string.Format("{0} not found", syntaxError));
} }
} }

Loading…
Cancel
Save