Browse Source

XML Parser: Initial support for Xml.Linq

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4580 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 16 years ago
parent
commit
8e03d90fdd
  1. 9
      samples/XmlDOM/XmlDOM.csproj
  2. 6
      samples/XmlDOM/XmlDOM.sln
  3. 132
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/RawObjects.cs
  4. 43
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/XmlParser.cs

9
samples/XmlDOM/XmlDOM.csproj

@ -27,9 +27,6 @@ @@ -27,9 +27,6 @@
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="ICSharpCode.AvalonEdit">
<HintPath>..\..\bin\ICSharpCode.AvalonEdit.dll</HintPath>
</Reference>
<Reference Include="PresentationCore">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
@ -61,5 +58,11 @@ @@ -61,5 +58,11 @@
<ItemGroup>
<Page Include="Window1.xaml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Libraries\AvalonEdit\ICSharpCode.AvalonEdit\ICSharpCode.AvalonEdit.csproj">
<Project>{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}</Project>
<Name>ICSharpCode.AvalonEdit</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project>

6
samples/XmlDOM/XmlDOM.sln

@ -4,6 +4,8 @@ Microsoft Visual Studio Solution File, Format Version 11.00 @@ -4,6 +4,8 @@ Microsoft Visual Studio Solution File, Format Version 11.00
# SharpDevelop 4.0.0.4567
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XmlDOM", "XmlDOM.csproj", "{AF8CA20E-58AC-423E-95A8-5AA464938D19}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.AvalonEdit", "..\..\src\Libraries\AvalonEdit\ICSharpCode.AvalonEdit\ICSharpCode.AvalonEdit.csproj", "{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -14,5 +16,9 @@ Global @@ -14,5 +16,9 @@ Global
{AF8CA20E-58AC-423E-95A8-5AA464938D19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF8CA20E-58AC-423E-95A8-5AA464938D19}.Release|Any CPU.Build.0 = Release|Any CPU
{AF8CA20E-58AC-423E-95A8-5AA464938D19}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|Any CPU.Build.0 = Release|Any CPU
{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
EndGlobal

132
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/RawObjects.cs

@ -8,7 +8,9 @@ @@ -8,7 +8,9 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using ICSharpCode.AvalonEdit.Document;
@ -54,7 +56,9 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -54,7 +56,9 @@ namespace ICSharpCode.AvalonEdit.XmlParser
protected void OnLocalDataChanged()
{
Log("XML DOM: Local data changed for {0}", this);
if (!inCloning) {
Log("XML DOM: Local data changed for {0}", this);
}
if (LocalDataChanged != null) {
LocalDataChanged(this, EventArgs.Empty);
}
@ -74,13 +78,15 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -74,13 +78,15 @@ namespace ICSharpCode.AvalonEdit.XmlParser
this.ReadCallID = new object();
}
// Disable some log messages during cloning
static bool inCloning = false;
public RawObject Clone()
{
RawObject clone = (RawObject)System.Activator.CreateInstance(this.GetType());
bool oldVal = LoggingEnabled;
LoggingEnabled = false;
inCloning = true;
clone.UpdateDataFrom(this);
LoggingEnabled = oldVal;
inCloning = false;
return clone;
}
@ -110,6 +116,13 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -110,6 +116,13 @@ namespace ICSharpCode.AvalonEdit.XmlParser
}
}
public static void LogLinq(string format, params object[] args)
{
if (LoggingEnabled) {
System.Diagnostics.Debug.WriteLine("XML Linq: " + format, args);
}
}
internal void OnInserting(RawObject parent, int index)
{
Log("XML DOM: Inserting {0} at index {1}", this, index);
@ -131,6 +144,17 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -131,6 +144,17 @@ namespace ICSharpCode.AvalonEdit.XmlParser
}
}
}
protected XName EncodeXName(string name, string ns)
{
if (string.IsNullOrEmpty(name)) name = "_";
name = XmlConvert.EncodeLocalName(name);
if (ns == null) ns = string.Empty;
ns = XmlConvert.EncodeLocalName(ns);
return XName.Get(name, ns);
}
}
public class RawDocument: RawObject
@ -179,10 +203,26 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -179,10 +203,26 @@ namespace ICSharpCode.AvalonEdit.XmlParser
public XDocument CreateXDocument(bool autoUpdate)
{
LogLinq("Creating XDocument");
XDocument doc = new XDocument();
doc.AddAnnotation(this);
UpdateXDocument(doc, autoUpdate);
this.Children.CollectionChanged += delegate { UpdateXDocument(doc, autoUpdate); };
return doc;
}
void UpdateXDocument(XDocument doc, bool autoUpdate)
{
RawElement root = this.Children.OfType<RawElement>().FirstOrDefault(x => x.StartTag.OpeningBracket == "<");
if (doc.Root.GetRawObject() != root) {
if (root != null) {
doc.ReplaceNodes(root.CreateXElement(autoUpdate));
} else {
doc.RemoveNodes();
}
}
}
public override string ToString()
{
return string.Format("[{0} Chld:{1}]", base.ToString(), this.Children.Count);
@ -192,6 +232,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -192,6 +232,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser
public class RawTag: RawObject
{
public string OpeningBracket { get; set; } // "<" or "</"
public string Namesapce { get; set; }
public string Name { get; set; }
public ObservableCollection<RawObject> Attributes { get; set; }
public string ClosingBracket { get; set; } // ">" or "/>" for well formed
@ -215,10 +256,12 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -215,10 +256,12 @@ namespace ICSharpCode.AvalonEdit.XmlParser
base.UpdateDataFrom(source);
RawTag src = (RawTag)source;
if (this.OpeningBracket != src.OpeningBracket ||
this.Namesapce != src.Namesapce ||
this.Name != src.Name ||
this.ClosingBracket != src.ClosingBracket)
{
this.OpeningBracket = src.OpeningBracket;
this.Namesapce = src.Namesapce;
this.Name = src.Name;
this.ClosingBracket = src.ClosingBracket;
OnLocalDataChanged();
@ -277,15 +320,44 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -277,15 +320,44 @@ namespace ICSharpCode.AvalonEdit.XmlParser
public XElement CreateXElement(bool autoUpdate)
{
XElement elem = new XElement(string.Empty);
UpdateXElement(elem);
if (autoUpdate) this.StartTag.LocalDataChanged += delegate { UpdateXElement(elem); };
LogLinq("Creating XElement '{0}'", this.StartTag.Name);
XElement elem = new XElement(EncodeXName(this.StartTag.Name, this.EndTag.Namesapce));
elem.AddAnnotation(this);
UpdateXElement(elem, autoUpdate);
UpdateXElementAttributes(elem, autoUpdate);
UpdateXElementChildren(elem, autoUpdate);
if (autoUpdate) {
this.StartTag.LocalDataChanged += delegate { UpdateXElement(elem, autoUpdate); };
this.StartTag.Attributes.CollectionChanged += delegate { UpdateXElementAttributes(elem, autoUpdate); };
this.Children.CollectionChanged += delegate { UpdateXElementChildren(elem, autoUpdate); };
}
return elem;
}
void UpdateXElement(XElement elem, bool autoUpdate)
{
LogLinq("Updating XElement '{0}'", this.StartTag.Name);
elem.Name = EncodeXName(this.StartTag.Name, this.EndTag.Namesapce);
}
void UpdateXElement(XElement elem)
internal void UpdateXElementAttributes(XElement elem, bool autoUpdate)
{
elem.Name = this.StartTag.Name;
List<XAttribute> xAttrs = new List<XAttribute>();
foreach(RawAttribute attr in this.StartTag.Attributes.OfType<RawAttribute>()) {
XAttribute existing = elem.Attributes().FirstOrDefault(x => x.GetRawObject() == attr);
xAttrs.Add(existing ?? attr.CreateXAttribute(autoUpdate));
}
elem.ReplaceAttributes(xAttrs.ToArray());
}
void UpdateXElementChildren(XElement elem, bool autoUpdate)
{
List<XElement> xElems = new List<XElement>();
foreach(RawElement rawElem in this.Children.OfType<RawElement>()) {
XElement existing = (XElement)elem.Nodes().FirstOrDefault(x => x.GetRawObject() == rawElem);
xElems.Add(existing ?? rawElem.CreateXElement(autoUpdate));
}
elem.ReplaceNodes(xElems);
}
public override string ToString()
@ -296,6 +368,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -296,6 +368,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser
public class RawAttribute: RawObject
{
public string Namesapce { get; set; }
public string Name { get; set; }
public string EqualsSign { get; set; }
public string Value { get; set; }
@ -305,10 +378,12 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -305,10 +378,12 @@ namespace ICSharpCode.AvalonEdit.XmlParser
if (this.ReadCallID == source.ReadCallID) return;
base.UpdateDataFrom(source);
RawAttribute src = (RawAttribute)source;
if (this.Name != src.Name ||
if (this.Namesapce != src.Namesapce ||
this.Name != src.Name ||
this.EqualsSign != src.EqualsSign ||
this.Value != src.Value)
{
this.Namesapce = src.Namesapce;
this.Name = src.Name;
this.EqualsSign = src.EqualsSign;
this.Value = src.Value;
@ -318,15 +393,27 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -318,15 +393,27 @@ namespace ICSharpCode.AvalonEdit.XmlParser
public XAttribute CreateXAttribute(bool autoUpdate)
{
XAttribute attr = new XAttribute(string.Empty, string.Empty);
UpdateXAttribute(attr);
if (autoUpdate) this.LocalDataChanged += delegate { UpdateXAttribute(attr); };
LogLinq("Creating XAttribute '{0}={1}'", this.Name, this.Value);
XAttribute attr = new XAttribute(EncodeXName(this.Name, this.Namesapce), string.Empty);
attr.AddAnnotation(this);
bool deleted = false;
UpdateXAttribute(attr, autoUpdate, ref deleted);
if (autoUpdate) this.LocalDataChanged += delegate { UpdateXAttribute(attr, autoUpdate, ref deleted); };
return attr;
}
void UpdateXAttribute(XAttribute attr)
void UpdateXAttribute(XAttribute attr, bool autoUpdate, ref bool deleted)
{
attr.Value = this.Value;
if (deleted) return;
LogLinq("Updating XAttribute '{0}={1}'", this.Name, this.Value);
if (attr.Name == EncodeXName(this.Name, this.Namesapce)) {
attr.Value = this.Value ?? string.Empty;
} else {
XElement parent = attr.Parent;
attr.Remove();
deleted = true;
((RawElement)parent.GetRawObject()).UpdateXElementAttributes(parent, autoUpdate);
}
}
public override string ToString()
@ -352,14 +439,17 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -352,14 +439,17 @@ namespace ICSharpCode.AvalonEdit.XmlParser
public XText CreateXText(bool autoUpdate)
{
LogLinq("Creating XText Length={0}", this.Value.Length);
XText text = new XText(string.Empty);
UpdateXText(text);
if (autoUpdate) this.LocalDataChanged += delegate { UpdateXText(text); };
text.AddAnnotation(this);
UpdateXText(text, autoUpdate);
if (autoUpdate) this.LocalDataChanged += delegate { UpdateXText(text, autoUpdate); };
return text;
}
void UpdateXText(XText text)
void UpdateXText(XText text, bool autoUpdate)
{
LogLinq("Updating XText Length={0}", this.Value.Length);
text.Value = this.Value;
}
@ -371,6 +461,12 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -371,6 +461,12 @@ namespace ICSharpCode.AvalonEdit.XmlParser
public static class RawUtils
{
public static RawObject GetRawObject(this XObject xObj)
{
if (xObj == null) return null;
return xObj.Annotation<RawObject>();
}
/// <summary>
/// Copy items from source list over to destination list.
/// Prefer updating items with matching offsets.

43
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/XmlParser.cs

@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Xml.Linq;
using ICSharpCode.AvalonEdit.Document;
@ -19,6 +20,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -19,6 +20,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser
public class XmlParser
{
RawDocument userDocument;
XDocument userLinqDocument;
TextDocument textDocument;
TextSegmentCollection<RawObject> userDom;
TextSegmentCollection<RawObject> parsedDom;
@ -36,6 +38,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -36,6 +38,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser
this.userDocument.ObjectDettached += delegate(object sender, RawObjectEventArgs e) {
this.userDom.Remove(e.Object);
};
this.userLinqDocument = this.userDocument.CreateXDocument(true);
}
public RawDocument Parse()
@ -108,6 +111,16 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -108,6 +111,16 @@ namespace ICSharpCode.AvalonEdit.XmlParser
}
}
bool TryRead(string text)
{
if (TryPeek(text)) {
currentLocation += text.Length;
return true;
} else {
return false;
}
}
bool TryPeek(char c)
{
if (currentLocation == input.Length) return false;
@ -141,7 +154,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -141,7 +154,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser
}
static char[] WhiteSpaceChars = new char[] {' ', '\n', '\r', '\t'};
static char[] WhiteSpaceAndReservedChars = new char[] {' ', '\n', '\r', '\t', '<', '=', '>', '/'};
static char[] WhiteSpaceAndReservedChars = new char[] {' ', '\n', '\r', '\t', '<', '=', '>', '/', ':', '?'};
bool? IsWhiteSpace()
{
@ -206,7 +219,11 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -206,7 +219,11 @@ namespace ICSharpCode.AvalonEdit.XmlParser
element.StartOffset = currentLocation;
element.StartTag = ReadTag(element);
// Read content
if (element.StartTag.ClosingBracket == ">") {
if (element.StartTag.ClosingBracket == ">" &&
element.StartTag.OpeningBracket != "<?" &&
element.StartTag.OpeningBracket != "<!" &&
element.StartTag.OpeningBracket != "<!--" )
{
while(true) {
if (IsEndOfFile()) {
break;
@ -244,10 +261,20 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -244,10 +261,20 @@ namespace ICSharpCode.AvalonEdit.XmlParser
tag.OpeningBracket = "<";
if (TryRead('/')) {
tag.OpeningBracket += "/";
} else if (TryRead('?')) {
tag.OpeningBracket += "?";
} else if (TryRead("!--")) {
tag.OpeningBracket += "!--";
} else if (TryRead('!')) {
tag.OpeningBracket += "!";
}
}
if (HasMoreData()) {
tag.Name = ReadName();
if (TryRead(':')) {
tag.Namesapce = tag.Name;
tag.Name = ReadName();
}
}
// Read attributes
while(true) {
@ -263,7 +290,13 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -263,7 +290,13 @@ namespace ICSharpCode.AvalonEdit.XmlParser
tag.ClosingBracket += ">";
}
break;
}
} else if (TryRead('?')) {
tag.ClosingBracket = "?";
if (TryRead('>')) {
tag.ClosingBracket += ">";
}
break;
}
if (TryPeek('<')) break;
if (HasMoreData()) {
tag.Attributes.Add(ReadAttribulte(tag));
@ -309,6 +342,10 @@ namespace ICSharpCode.AvalonEdit.XmlParser @@ -309,6 +342,10 @@ namespace ICSharpCode.AvalonEdit.XmlParser
attr.StartOffset = currentLocation;
if (HasMoreData()) {
attr.Name = ReadName();
if (TryRead(':')) {
attr.Namesapce = attr.Name;
attr.Name = ReadName();
}
}
int checkpoint = currentLocation;
attr.EqualsSign = string.Empty;

Loading…
Cancel
Save