Browse Source
git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4578 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
12 changed files with 1224 additions and 0 deletions
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
<Application x:Class="XmlDOM.App" |
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
StartupUri="Window1.xaml"> |
||||
<Application.Resources> |
||||
|
||||
</Application.Resources> |
||||
</Application> |
||||
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
using System; |
||||
using System.Windows; |
||||
using System.Data; |
||||
using System.Xml; |
||||
using System.Configuration; |
||||
|
||||
namespace XmlDOM |
||||
{ |
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application |
||||
{ |
||||
public App() |
||||
{ |
||||
InitializeComponent(); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
|
||||
#region Using directives
|
||||
|
||||
using System; |
||||
using System.Reflection; |
||||
using System.Runtime.InteropServices; |
||||
|
||||
#endregion
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("XmlDOM")] |
||||
[assembly: AssemblyDescription("")] |
||||
[assembly: AssemblyConfiguration("")] |
||||
[assembly: AssemblyCompany("")] |
||||
[assembly: AssemblyProduct("XmlDOM")] |
||||
[assembly: AssemblyCopyright("Copyright 2009")] |
||||
[assembly: AssemblyTrademark("")] |
||||
[assembly: AssemblyCulture("")] |
||||
|
||||
// This sets the default COM visibility of types in the assembly to invisible.
|
||||
// If you need to expose a type to COM, use [ComVisible(true)] on that type.
|
||||
[assembly: ComVisible(false)] |
||||
|
||||
// The assembly version has following format :
|
||||
//
|
||||
// Major.Minor.Build.Revision
|
||||
//
|
||||
// You can specify all the values or you can use the default the Revision and
|
||||
// Build Numbers by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("1.0.*")] |
||||
@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
|
||||
#region Using directives
|
||||
|
||||
using System.Resources; |
||||
using System.Windows; |
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
//In order to begin building localizable applications, set
|
||||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||
//inside a <PropertyGroup>. For example, if you are using US english
|
||||
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||
//the line below to match the UICulture setting in the project file.
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
|
||||
[assembly: ThemeInfo( |
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)] |
||||
@ -0,0 +1,40 @@
@@ -0,0 +1,40 @@
|
||||
<Window x:Class="XmlDOM.Window1" |
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
xmlns:clr="clr-namespace:ICSharpCode.AvalonEdit.XmlParser;assembly=ICSharpCode.AvalonEdit" |
||||
xmlns:ic="http://icsharpcode.net/sharpdevelop/avalonedit" |
||||
Title="XmlEditor" Height="450" Width="600" |
||||
> |
||||
<Window.Resources> |
||||
<Storyboard x:Key="anim"> |
||||
<ColorAnimation Storyboard.TargetProperty="(TextBlock.Background).(SolidColorBrush.Color)" To="Transparent" Duration="0:0:4"/> |
||||
</Storyboard> |
||||
<HierarchicalDataTemplate DataType="{x:Type clr:RawDocument}" ItemsSource="{Binding Helper_Elements}"> |
||||
<TextBlock Text="XML Document" Margin="2"/> |
||||
</HierarchicalDataTemplate> |
||||
<HierarchicalDataTemplate DataType="{x:Type clr:RawElement}" ItemsSource="{Binding Helper_AttributesAndElements}"> |
||||
<TextBlock Text="{Binding StartTag.Name}" Margin="2" Initialized="BindElement"/> |
||||
</HierarchicalDataTemplate> |
||||
<HierarchicalDataTemplate DataType="{x:Type clr:RawAttribute}"> |
||||
<StackPanel Orientation="Horizontal" Margin="2"> |
||||
<TextBlock Text="{Binding Name}" Foreground="Blue" Initialized="BindObject"/> |
||||
<TextBlock Text="=" VerticalAlignment="Center"/> |
||||
<TextBlock Text="{Binding Value}" Foreground="Blue" Initialized="BindObject"/> |
||||
</StackPanel> |
||||
</HierarchicalDataTemplate> |
||||
<HierarchicalDataTemplate DataType="{x:Type clr:RawText}" ItemContainerStyle="{x:Null}"> |
||||
<Border BorderBrush="LightGray" Height="1" BorderThickness="1"/> |
||||
</HierarchicalDataTemplate> |
||||
</Window.Resources> |
||||
<Grid> |
||||
<Grid.ColumnDefinitions> |
||||
<ColumnDefinition Width="2*"/> |
||||
<ColumnDefinition Width="*"/> |
||||
</Grid.ColumnDefinitions> |
||||
<ic:TextEditor x:Name="editor"/> |
||||
<DockPanel Grid.Column="1"> |
||||
<Button DockPanel.Dock="Top" Content="Parse" Click="Button_Click"/> |
||||
<TreeView Name="treeView"/> |
||||
</DockPanel> |
||||
</Grid> |
||||
</Window> |
||||
@ -0,0 +1,82 @@
@@ -0,0 +1,82 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Text; |
||||
using System.Windows; |
||||
using System.Windows.Controls; |
||||
using System.Windows.Data; |
||||
using System.Windows.Documents; |
||||
using System.Windows.Input; |
||||
using System.Windows.Media; |
||||
using System.Windows.Media.Animation; |
||||
using System.Windows.Threading; |
||||
|
||||
using ICSharpCode.AvalonEdit.XmlParser; |
||||
|
||||
namespace XmlDOM |
||||
{ |
||||
/// <summary>
|
||||
/// Interaction logic for Window1.xaml
|
||||
/// </summary>
|
||||
public partial class Window1 : Window |
||||
{ |
||||
XmlParser parser; |
||||
|
||||
public Window1() |
||||
{ |
||||
InitializeComponent(); |
||||
} |
||||
|
||||
protected override void OnInitialized(EventArgs e) |
||||
{ |
||||
parser = new XmlParser(editor.Document); |
||||
|
||||
DispatcherTimer timer = new DispatcherTimer(); |
||||
timer.Interval = TimeSpan.FromSeconds(0.25); |
||||
timer.Tick += delegate { Button_Click(null, null); }; |
||||
timer.Start(); |
||||
|
||||
base.OnInitialized(e); |
||||
} |
||||
|
||||
void Button_Click(object sender, RoutedEventArgs e) |
||||
{ |
||||
RawDocument doc = parser.Parse(); |
||||
if (treeView.Items.Count == 0) { |
||||
treeView.Items.Add(doc); |
||||
} |
||||
} |
||||
|
||||
void BindObject(object sender, EventArgs e) |
||||
{ |
||||
TextBlock textBlock = (TextBlock)sender; |
||||
RawObject node = (RawObject)textBlock.DataContext; |
||||
node.LocalDataChanged += delegate { |
||||
BindingOperations.GetBindingExpression(textBlock, TextBlock.TextProperty).UpdateTarget(); |
||||
textBlock.Background = new SolidColorBrush(Colors.LightGreen); |
||||
Storyboard sb = ((Storyboard)this.FindResource("anim")); |
||||
Storyboard.SetTarget(sb, textBlock); |
||||
sb.Begin(); |
||||
}; |
||||
} |
||||
|
||||
void BindElement(object sender, EventArgs e) |
||||
{ |
||||
TextBlock textBlock = (TextBlock)sender; |
||||
RawElement node = (RawElement)textBlock.DataContext; |
||||
node.StartTag.LocalDataChanged += delegate { |
||||
BindingOperations.GetBindingExpression(textBlock, TextBlock.TextProperty).UpdateTarget(); |
||||
textBlock.Background = new SolidColorBrush(Colors.LightGreen); |
||||
Storyboard sb = ((Storyboard)this.FindResource("anim")); |
||||
Storyboard.SetTarget(sb, textBlock); |
||||
sb.Begin(); |
||||
}; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,65 @@
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build"> |
||||
<PropertyGroup> |
||||
<ProjectGuid>{AF8CA20E-58AC-423E-95A8-5AA464938D19}</ProjectGuid> |
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
||||
<OutputType>WinExe</OutputType> |
||||
<RootNamespace>XmlDOM</RootNamespace> |
||||
<AssemblyName>XmlDOM</AssemblyName> |
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> |
||||
<AppDesignerFolder>Properties</AppDesignerFolder> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> |
||||
<OutputPath>bin\Debug\</OutputPath> |
||||
<DebugSymbols>True</DebugSymbols> |
||||
<DebugType>Full</DebugType> |
||||
<Optimize>False</Optimize> |
||||
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow> |
||||
<DefineConstants>DEBUG;TRACE</DefineConstants> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> |
||||
<OutputPath>bin\Release\</OutputPath> |
||||
<DebugSymbols>False</DebugSymbols> |
||||
<DebugType>None</DebugType> |
||||
<Optimize>True</Optimize> |
||||
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> |
||||
<DefineConstants>TRACE</DefineConstants> |
||||
</PropertyGroup> |
||||
<ItemGroup> |
||||
<Reference Include="ICSharpCode.AvalonEdit"> |
||||
<HintPath>..\..\bin\ICSharpCode.AvalonEdit.dll</HintPath> |
||||
</Reference> |
||||
<Reference Include="PresentationCore"> |
||||
<RequiredTargetFramework>3.0</RequiredTargetFramework> |
||||
</Reference> |
||||
<Reference Include="PresentationFramework"> |
||||
<RequiredTargetFramework>3.0</RequiredTargetFramework> |
||||
</Reference> |
||||
<Reference Include="System" /> |
||||
<Reference Include="System.Data" /> |
||||
<Reference Include="System.Xml" /> |
||||
<Reference Include="WindowsBase"> |
||||
<RequiredTargetFramework>3.0</RequiredTargetFramework> |
||||
</Reference> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<ApplicationDefinition Include="App.xaml" /> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<Compile Include="App.xaml.cs"> |
||||
<SubType>Code</SubType> |
||||
<DependentUpon>App.xaml</DependentUpon> |
||||
</Compile> |
||||
<Compile Include="Properties\AssemblyInfo.cs" /> |
||||
<Compile Include="Properties\WPFAssemblyInfo.cs" /> |
||||
<Compile Include="Window1.xaml.cs"> |
||||
<SubType>Code</SubType> |
||||
<DependentUpon>Window1.xaml</DependentUpon> |
||||
</Compile> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<Page Include="Window1.xaml" /> |
||||
</ItemGroup> |
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> |
||||
</Project> |
||||
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00 |
||||
# Visual Studio 10 |
||||
# SharpDevelop 4.0.0.4567 |
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XmlDOM", "XmlDOM.csproj", "{AF8CA20E-58AC-423E-95A8-5AA464938D19}" |
||||
EndProject |
||||
Global |
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
||||
Debug|Any CPU = Debug|Any CPU |
||||
Release|Any CPU = Release|Any CPU |
||||
EndGlobalSection |
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution |
||||
{AF8CA20E-58AC-423E-95A8-5AA464938D19}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
{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 |
||||
EndGlobalSection |
||||
EndGlobal |
||||
@ -0,0 +1,112 @@
@@ -0,0 +1,112 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Collections.ObjectModel; |
||||
using System.Collections.Specialized; |
||||
using System.Linq; |
||||
|
||||
// Missing XML comment
|
||||
#pragma warning disable 1591
|
||||
|
||||
namespace ICSharpCode.AvalonEdit.XmlParser |
||||
{ |
||||
public class FilteredObservableCollection<T>: ObservableCollection<T> |
||||
{ |
||||
ObservableCollection<T> source; |
||||
Predicate<T> condition; |
||||
List<int> srcPtrs = new List<int>(); |
||||
|
||||
public FilteredObservableCollection(ObservableCollection<T> source, Predicate<T> condition) |
||||
{ |
||||
this.source = source; |
||||
this.condition = condition; |
||||
|
||||
for(int i = 0; i < source.Count; i++) { |
||||
if (condition(source[i])) { |
||||
int index = srcPtrs.Count; |
||||
this.InsertItem(index, source[i]); |
||||
srcPtrs.Insert(index, i); |
||||
} |
||||
} |
||||
|
||||
this.source.CollectionChanged += new NotifyCollectionChangedEventHandler(FilteredObservableCollection_CollectionChanged); |
||||
} |
||||
|
||||
void FilteredObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) |
||||
{ |
||||
if (e.Action == NotifyCollectionChangedAction.Remove) { |
||||
// Remove the item from our collection
|
||||
if (condition((T)e.OldItems[0])) { |
||||
int index = srcPtrs.IndexOf(e.OldStartingIndex); |
||||
this.RemoveAt(index); |
||||
srcPtrs.RemoveAt(index); |
||||
} |
||||
// Update pointers
|
||||
for(int i = 0; i < srcPtrs.Count; i++) { |
||||
if (srcPtrs[i] > e.OldStartingIndex) { |
||||
srcPtrs[i]--; |
||||
} |
||||
} |
||||
} |
||||
if (e.Action == NotifyCollectionChangedAction.Add) { |
||||
// Update pointers
|
||||
for(int i = 0; i < srcPtrs.Count; i++) { |
||||
if (srcPtrs[i] >= e.NewStartingIndex) { |
||||
srcPtrs[i]++; |
||||
} |
||||
} |
||||
// Add item to collection
|
||||
if (condition((T)e.NewItems[0])) { |
||||
int index = srcPtrs.FindIndex(srcPtr => srcPtr >= e.NewStartingIndex); |
||||
if (index == -1) index = srcPtrs.Count; |
||||
this.InsertItem(index, (T)e.NewItems[0]); |
||||
srcPtrs.Insert(index, e.NewStartingIndex); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
public class MergedObservableCollection<T>: ObservableCollection<T> |
||||
{ |
||||
ObservableCollection<T> a; |
||||
ObservableCollection<T> b; |
||||
|
||||
public MergedObservableCollection(ObservableCollection<T> a, ObservableCollection<T> b) |
||||
{ |
||||
this.a = a; |
||||
this.b = b; |
||||
|
||||
foreach(T item in a) this.Add(item); |
||||
foreach(T item in b) this.Add(item); |
||||
|
||||
this.a.CollectionChanged += new NotifyCollectionChangedEventHandler(MergedObservableCollection_CollectionAChanged); |
||||
this.b.CollectionChanged += new NotifyCollectionChangedEventHandler(MergedObservableCollection_CollectionBChanged); |
||||
} |
||||
|
||||
void MergedObservableCollection_CollectionAChanged(object sender, NotifyCollectionChangedEventArgs e) |
||||
{ |
||||
if (e.Action == NotifyCollectionChangedAction.Remove) { |
||||
this.RemoveAt(e.OldStartingIndex); |
||||
} |
||||
if (e.Action == NotifyCollectionChangedAction.Add) { |
||||
this.InsertItem(e.NewStartingIndex, (T)e.NewItems[0]); |
||||
} |
||||
} |
||||
|
||||
void MergedObservableCollection_CollectionBChanged(object sender, NotifyCollectionChangedEventArgs e) |
||||
{ |
||||
if (e.Action == NotifyCollectionChangedAction.Remove) { |
||||
this.RemoveAt(e.OldStartingIndex + a.Count); |
||||
} |
||||
if (e.Action == NotifyCollectionChangedAction.Add) { |
||||
this.InsertItem(e.NewStartingIndex + a.Count, (T)e.NewItems[0]); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,455 @@
@@ -0,0 +1,455 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Collections.ObjectModel; |
||||
using System.Linq; |
||||
using System.Xml.Linq; |
||||
|
||||
using ICSharpCode.AvalonEdit.Document; |
||||
|
||||
// Missing XML comment
|
||||
#pragma warning disable 1591
|
||||
|
||||
namespace ICSharpCode.AvalonEdit.XmlParser |
||||
{ |
||||
public class RawObjectEventArgs: EventArgs |
||||
{ |
||||
public RawObject Object { get; set; } |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// The base class for all XML objects. The objects store the precise text
|
||||
/// representation so that generated text will preciesly match original.
|
||||
/// </summary>
|
||||
public abstract class RawObject: TextSegment |
||||
{ |
||||
/// <summary>
|
||||
/// Unique identifier for the specific call of parsing read function.
|
||||
/// It is used to uniquely identify all object data (including nested).
|
||||
/// </summary>
|
||||
internal object ReadCallID { get; private set; } |
||||
|
||||
public RawObject Parent { get; set; } |
||||
|
||||
public RawDocument Document { |
||||
get { |
||||
if (this.Parent != null) { |
||||
return this.Parent.Document; |
||||
} else if (this is RawDocument) { |
||||
return (RawDocument)this; |
||||
} else { |
||||
return null; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// <summary> Occurs when the value of any local properties changes. Nested changes do not cause the event to occur </summary>
|
||||
public event EventHandler LocalDataChanged; |
||||
|
||||
protected void OnLocalDataChanged() |
||||
{ |
||||
Log("XML DOM: Local data changed for {0}", this); |
||||
if (LocalDataChanged != null) { |
||||
LocalDataChanged(this, EventArgs.Empty); |
||||
} |
||||
} |
||||
|
||||
public new int EndOffset { |
||||
get { |
||||
return this.StartOffset + this.Length; |
||||
} |
||||
set { |
||||
this.Length = value - this.StartOffset; |
||||
} |
||||
} |
||||
|
||||
public RawObject() |
||||
{ |
||||
this.ReadCallID = new object(); |
||||
} |
||||
|
||||
public RawObject Clone() |
||||
{ |
||||
RawObject clone = (RawObject)System.Activator.CreateInstance(this.GetType()); |
||||
bool oldVal = LoggingEnabled; |
||||
LoggingEnabled = false; |
||||
clone.UpdateDataFrom(this); |
||||
LoggingEnabled = oldVal; |
||||
return clone; |
||||
} |
||||
|
||||
public virtual IEnumerable<RawObject> GetSeftAndAllNestedObjects() |
||||
{ |
||||
yield return this; |
||||
} |
||||
|
||||
public virtual void UpdateDataFrom(RawObject source) |
||||
{ |
||||
this.ReadCallID = source.ReadCallID; |
||||
this.StartOffset = source.StartOffset; |
||||
this.EndOffset = source.EndOffset; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return string.Format("{0}({1}-{2})", this.GetType().Name.Remove(0, 3), this.StartOffset, this.EndOffset); |
||||
} |
||||
|
||||
public static bool LoggingEnabled = true; |
||||
|
||||
public static void Log(string format, params object[] args) |
||||
{ |
||||
if (LoggingEnabled) { |
||||
System.Diagnostics.Debug.WriteLine(format, args); |
||||
} |
||||
} |
||||
|
||||
internal void OnInserting(RawObject parent, int index) |
||||
{ |
||||
Log("XML DOM: Inserting {0} at index {1}", this, index); |
||||
this.Parent = parent; |
||||
if (this.Document != null) { |
||||
foreach(RawObject obj in GetSeftAndAllNestedObjects()) { |
||||
this.Document.OnObjectAttached(new RawObjectEventArgs() { Object = obj }); |
||||
} |
||||
} |
||||
} |
||||
|
||||
internal void OnRemoving(RawObject parent, int index) |
||||
{ |
||||
Log("XML DOM: Removing {0} at index {1}", this, index); |
||||
this.Parent = null; |
||||
if (this.Document != null) { |
||||
foreach(RawObject obj in GetSeftAndAllNestedObjects()) { |
||||
this.Document.OnObjectDettached(new RawObjectEventArgs() { Object = obj }); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
public class RawDocument: RawObject |
||||
{ |
||||
public ObservableCollection<RawObject> Children { get; set; } |
||||
|
||||
public event EventHandler<RawObjectEventArgs> ObjectAttached; |
||||
public event EventHandler<RawObjectEventArgs> ObjectDettached; |
||||
|
||||
public ObservableCollection<RawObject> Helper_Elements { |
||||
get { |
||||
return new FilteredObservableCollection<RawObject>(this.Children, x => x is RawElement); |
||||
} |
||||
} |
||||
|
||||
internal void OnObjectAttached(RawObjectEventArgs e) |
||||
{ |
||||
if (ObjectAttached != null) ObjectAttached(this, e); |
||||
} |
||||
|
||||
internal void OnObjectDettached(RawObjectEventArgs e) |
||||
{ |
||||
if (ObjectDettached != null) ObjectDettached(this, e); |
||||
} |
||||
|
||||
public RawDocument() |
||||
{ |
||||
this.Children = new ObservableCollection<RawObject>(); |
||||
} |
||||
|
||||
public override IEnumerable<RawObject> GetSeftAndAllNestedObjects() |
||||
{ |
||||
return Enumerable.Union( |
||||
new RawObject[] { this }, |
||||
this.Children.SelectMany(x => x.GetSeftAndAllNestedObjects()) |
||||
); |
||||
} |
||||
|
||||
public override void UpdateDataFrom(RawObject source) |
||||
{ |
||||
if (this.ReadCallID == source.ReadCallID) return; |
||||
base.UpdateDataFrom(source); |
||||
RawDocument src = (RawDocument)source; |
||||
RawUtils.SmartListUpdate(src.Children, this.Children, this); |
||||
} |
||||
|
||||
public XDocument CreateXDocument(bool autoUpdate) |
||||
{ |
||||
XDocument doc = new XDocument(); |
||||
return doc; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return string.Format("[{0} Chld:{1}]", base.ToString(), this.Children.Count); |
||||
} |
||||
} |
||||
|
||||
public class RawTag: RawObject |
||||
{ |
||||
public string OpeningBracket { get; set; } // "<" or "</"
|
||||
public string Name { get; set; } |
||||
public ObservableCollection<RawObject> Attributes { get; set; } |
||||
public string ClosingBracket { get; set; } // ">" or "/>" for well formed
|
||||
|
||||
public RawTag() |
||||
{ |
||||
this.Attributes = new ObservableCollection<RawObject>(); |
||||
} |
||||
|
||||
public override IEnumerable<RawObject> GetSeftAndAllNestedObjects() |
||||
{ |
||||
return Enumerable.Union( |
||||
new RawObject[] { this }, |
||||
this.Attributes // Have no nested objects
|
||||
); |
||||
} |
||||
|
||||
public override void UpdateDataFrom(RawObject source) |
||||
{ |
||||
if (this.ReadCallID == source.ReadCallID) return; |
||||
base.UpdateDataFrom(source); |
||||
RawTag src = (RawTag)source; |
||||
if (this.OpeningBracket != src.OpeningBracket || |
||||
this.Name != src.Name || |
||||
this.ClosingBracket != src.ClosingBracket) |
||||
{ |
||||
this.OpeningBracket = src.OpeningBracket; |
||||
this.Name = src.Name; |
||||
this.ClosingBracket = src.ClosingBracket; |
||||
OnLocalDataChanged(); |
||||
} |
||||
RawUtils.SmartListUpdate(src.Attributes, this.Attributes, this); |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return string.Format("[{0} '{1}{2}{3}' Attr:{4}]", base.ToString(), this.OpeningBracket, this.Name, this.ClosingBracket, this.Attributes.Count); |
||||
} |
||||
} |
||||
|
||||
public class RawElement: RawObject |
||||
{ |
||||
public RawTag StartTag { get; set; } |
||||
public ObservableCollection<RawObject> Children { get; set; } |
||||
public bool HasEndTag { get; set; } |
||||
public RawTag EndTag { get; set; } |
||||
|
||||
public ObservableCollection<RawObject> Helper_AttributesAndElements { |
||||
get { |
||||
return new MergedObservableCollection<RawObject>( |
||||
new FilteredObservableCollection<RawObject>(this.StartTag.Attributes, x => x is RawAttribute), |
||||
new FilteredObservableCollection<RawObject>(this.Children, x => x is RawElement) |
||||
); |
||||
} |
||||
} |
||||
|
||||
public RawElement() |
||||
{ |
||||
this.StartTag = new RawTag() { Parent = this }; |
||||
this.Children = new ObservableCollection<RawObject>(); |
||||
this.EndTag = new RawTag() { Parent = this }; |
||||
} |
||||
|
||||
public override IEnumerable<RawObject> GetSeftAndAllNestedObjects() |
||||
{ |
||||
return new IEnumerable<RawObject>[] { |
||||
new RawObject[] { this }, |
||||
this.StartTag.GetSeftAndAllNestedObjects(), |
||||
this.Children.SelectMany(x => x.GetSeftAndAllNestedObjects()), |
||||
this.EndTag.GetSeftAndAllNestedObjects() |
||||
}.SelectMany(x => x); |
||||
} |
||||
|
||||
public override void UpdateDataFrom(RawObject source) |
||||
{ |
||||
if (this.ReadCallID == source.ReadCallID) return; |
||||
base.UpdateDataFrom(source); |
||||
RawElement src = (RawElement)source; |
||||
this.StartTag.UpdateDataFrom(src.StartTag); |
||||
RawUtils.SmartListUpdate(src.Children, this.Children, this); |
||||
this.EndTag.UpdateDataFrom(src.EndTag); |
||||
} |
||||
|
||||
public XElement CreateXElement(bool autoUpdate) |
||||
{ |
||||
XElement elem = new XElement(string.Empty); |
||||
UpdateXElement(elem); |
||||
if (autoUpdate) this.StartTag.LocalDataChanged += delegate { UpdateXElement(elem); }; |
||||
return elem; |
||||
} |
||||
|
||||
void UpdateXElement(XElement elem) |
||||
{ |
||||
elem.Name = this.StartTag.Name; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return string.Format("[{0} '{1}{2}{3}' Attr:{4} Chld:{5}]", base.ToString(), this.StartTag.OpeningBracket, this.StartTag.Name, this.StartTag.ClosingBracket, this.StartTag.Attributes.Count, this.Children.Count); |
||||
} |
||||
} |
||||
|
||||
public class RawAttribute: RawObject |
||||
{ |
||||
public string Name { get; set; } |
||||
public string EqualsSign { get; set; } |
||||
public string Value { get; set; } |
||||
|
||||
public override void UpdateDataFrom(RawObject source) |
||||
{ |
||||
if (this.ReadCallID == source.ReadCallID) return; |
||||
base.UpdateDataFrom(source); |
||||
RawAttribute src = (RawAttribute)source; |
||||
if (this.Name != src.Name || |
||||
this.EqualsSign != src.EqualsSign || |
||||
this.Value != src.Value) |
||||
{ |
||||
this.Name = src.Name; |
||||
this.EqualsSign = src.EqualsSign; |
||||
this.Value = src.Value; |
||||
OnLocalDataChanged(); |
||||
} |
||||
} |
||||
|
||||
public XAttribute CreateXAttribute(bool autoUpdate) |
||||
{ |
||||
XAttribute attr = new XAttribute(string.Empty, string.Empty); |
||||
UpdateXAttribute(attr); |
||||
if (autoUpdate) this.LocalDataChanged += delegate { UpdateXAttribute(attr); }; |
||||
return attr; |
||||
} |
||||
|
||||
void UpdateXAttribute(XAttribute attr) |
||||
{ |
||||
attr.Value = this.Value; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return string.Format("[{0} '{1}{2}{3}']", base.ToString(), this.Name, this.EqualsSign, this.Value); |
||||
} |
||||
} |
||||
|
||||
public class RawText: RawObject |
||||
{ |
||||
public string Value { get; set; } |
||||
|
||||
public override void UpdateDataFrom(RawObject source) |
||||
{ |
||||
if (this.ReadCallID == source.ReadCallID) return; |
||||
base.UpdateDataFrom(source); |
||||
RawText src = (RawText)source; |
||||
if (this.Value != src.Value) { |
||||
this.Value = src.Value; |
||||
OnLocalDataChanged(); |
||||
} |
||||
} |
||||
|
||||
public XText CreateXText(bool autoUpdate) |
||||
{ |
||||
XText text = new XText(string.Empty); |
||||
UpdateXText(text); |
||||
if (autoUpdate) this.LocalDataChanged += delegate { UpdateXText(text); }; |
||||
return text; |
||||
} |
||||
|
||||
void UpdateXText(XText text) |
||||
{ |
||||
text.Value = this.Value; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return string.Format("[{0} Text.Length={1}]", base.ToString(), this.Value.Length); |
||||
} |
||||
} |
||||
|
||||
public static class RawUtils |
||||
{ |
||||
/// <summary>
|
||||
/// Copy items from source list over to destination list.
|
||||
/// Prefer updating items with matching offsets.
|
||||
/// </summary>
|
||||
public static void SmartListUpdate(IList<RawObject> srcList, IList<RawObject> dstList, RawObject dstListOwner) |
||||
{ |
||||
// Items up to 'i' shall be matching
|
||||
for(int i = 0; i < srcList.Count;) { |
||||
// Item is missing - 'i' is invalid index
|
||||
if (i >= dstList.Count) { |
||||
RawObject clone = srcList[i].Clone(); |
||||
clone.OnInserting(dstListOwner, i); |
||||
dstList.Insert(i, clone); |
||||
i++; continue; |
||||
} |
||||
RawObject srcItem = srcList[i]; |
||||
RawObject dstItem = dstList[i]; |
||||
// Matching and updated
|
||||
if (srcItem.ReadCallID == dstItem.ReadCallID) { |
||||
i++; continue; |
||||
} |
||||
// Offsets and types are matching
|
||||
if (srcItem.StartOffset == dstItem.StartOffset && |
||||
srcItem.GetType() == dstItem.GetType()) |
||||
{ |
||||
dstItem.UpdateDataFrom(srcItem); |
||||
i++; continue; |
||||
} |
||||
// Try to be smart by inserting or removing items
|
||||
// Dst offset matches with future src
|
||||
for(int srcItemIndex = i; srcItemIndex < srcList.Count; srcItemIndex++) { |
||||
RawObject src = srcList[srcItemIndex]; |
||||
if (src.StartOffset == dstItem.StartOffset && src.GetType() == dstItem.GetType()) { |
||||
for(int j = i; j < srcItemIndex; j++) { |
||||
RawObject clone = srcList[j].Clone(); |
||||
clone.OnInserting(dstListOwner, j); |
||||
dstList.Insert(j, clone); |
||||
} |
||||
i = srcItemIndex; |
||||
goto continue2; |
||||
} |
||||
} |
||||
// Scr offset matches with future dst
|
||||
for(int dstItemIndex = i; dstItemIndex < dstList.Count; dstItemIndex++) { |
||||
RawObject dst = dstList[dstItemIndex]; |
||||
if (srcItem.StartOffset == dst.StartOffset && srcItem.GetType() == dst.GetType()) { |
||||
for(int j = 0; j < dstItemIndex - i; j++) { |
||||
dstList[i].OnRemoving(dstListOwner, i); |
||||
dstList.RemoveAt(i); |
||||
} |
||||
goto continue2; |
||||
} |
||||
} |
||||
// No matches found - just update
|
||||
if (dstItem.GetType() == srcItem.GetType()) { |
||||
dstItem.UpdateDataFrom(srcItem); |
||||
i++; continue; |
||||
} |
||||
// Remove whitespace in hope that element update will occur next
|
||||
if (dstItem is RawText) { |
||||
dstList[i].OnRemoving(dstListOwner, i); |
||||
dstList.RemoveAt(i); |
||||
continue; |
||||
} |
||||
// Otherwise just add the item
|
||||
{ |
||||
RawObject clone = srcList[i].Clone(); |
||||
clone.OnInserting(dstListOwner, i); |
||||
dstList.Insert(i, clone); |
||||
i++; continue; |
||||
} |
||||
} |
||||
// Remove extra items
|
||||
while(dstList.Count > srcList.Count) { |
||||
dstList[srcList.Count].OnRemoving(dstListOwner, srcList.Count); |
||||
dstList.RemoveAt(srcList.Count); |
||||
} |
||||
// Continue for inner loops
|
||||
continue2:; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,363 @@
@@ -0,0 +1,363 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Diagnostics; |
||||
using System.Linq; |
||||
|
||||
using ICSharpCode.AvalonEdit.Document; |
||||
|
||||
// Missing XML comment
|
||||
#pragma warning disable 1591
|
||||
|
||||
namespace ICSharpCode.AvalonEdit.XmlParser |
||||
{ |
||||
public class XmlParser |
||||
{ |
||||
RawDocument userDocument; |
||||
TextDocument textDocument; |
||||
TextSegmentCollection<RawObject> userDom; |
||||
TextSegmentCollection<RawObject> parsedDom; |
||||
|
||||
public XmlParser(TextDocument textDocument) |
||||
{ |
||||
this.userDocument = new RawDocument(); |
||||
this.textDocument = textDocument; |
||||
this.userDom = new TextSegmentCollection<RawObject>(textDocument); |
||||
this.parsedDom = new TextSegmentCollection<RawObject>(textDocument); |
||||
this.textDocument.Changed += TextDocument_Changed; |
||||
this.userDocument.ObjectAttached += delegate(object sender, RawObjectEventArgs e) { |
||||
this.userDom.Add(e.Object); |
||||
}; |
||||
this.userDocument.ObjectDettached += delegate(object sender, RawObjectEventArgs e) { |
||||
this.userDom.Remove(e.Object); |
||||
}; |
||||
} |
||||
|
||||
public RawDocument Parse() |
||||
{ |
||||
currentLocation = 0; |
||||
input = textDocument.Text; |
||||
|
||||
RawDocument parsedDocument = ReadDocument(); |
||||
userDocument.UpdateDataFrom(parsedDocument); |
||||
return userDocument; |
||||
} |
||||
|
||||
void TextDocument_Changed(object sender, DocumentChangeEventArgs e) |
||||
{ |
||||
int start = e.Offset - 2; |
||||
int end = e.Offset + e.InsertionLength + 2; |
||||
start = Math.Max(Math.Min(start, textDocument.TextLength - 1), 0); |
||||
end = Math.Max(Math.Min(end, textDocument.TextLength - 1), 0); |
||||
foreach(RawObject obj in parsedDom.FindOverlappingSegments(start, end - start)) { |
||||
parsedDom.Remove(obj); |
||||
Log("Removed cached item: {0}", obj); |
||||
} |
||||
} |
||||
|
||||
T ReadFromCache<T>(int location) where T: RawObject |
||||
{ |
||||
RawObject obj = parsedDom.FindFirstSegmentWithStartAfter(location); |
||||
while(obj != null && obj.StartOffset == location) { |
||||
if (obj is T) { |
||||
currentLocation += obj.Length; |
||||
return (T)obj; |
||||
} |
||||
obj = parsedDom.GetNextSegment(obj); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
void Log(string text, params object[] pars) |
||||
{ |
||||
System.Diagnostics.Debug.WriteLine("XML Parser: " + text, pars); |
||||
} |
||||
|
||||
void LogParsed(RawObject obj) |
||||
{ |
||||
System.Diagnostics.Debug.WriteLine("XML Parser: Parsed " + obj.ToString()); |
||||
} |
||||
|
||||
string input; |
||||
int currentLocation; |
||||
|
||||
bool IsEndOfFile() |
||||
{ |
||||
return currentLocation == input.Length; |
||||
} |
||||
|
||||
bool HasMoreData() |
||||
{ |
||||
return currentLocation < input.Length; |
||||
} |
||||
|
||||
bool TryRead(char c) |
||||
{ |
||||
if (currentLocation == input.Length) return false; |
||||
|
||||
if (input[currentLocation] == c) { |
||||
currentLocation++; |
||||
return true; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
bool TryPeek(char c) |
||||
{ |
||||
if (currentLocation == input.Length) return false; |
||||
|
||||
return input[currentLocation] == c; |
||||
} |
||||
|
||||
bool TryPeek(string text) |
||||
{ |
||||
if (currentLocation + text.Length > input.Length) return false; |
||||
|
||||
return input.Substring(currentLocation, text.Length) == text; |
||||
} |
||||
|
||||
bool TryMoveTo(params char[] c) |
||||
{ |
||||
while(true) { |
||||
if (currentLocation == input.Length) return false; |
||||
if (c.Contains(input[currentLocation])) return true; |
||||
currentLocation++; |
||||
} |
||||
} |
||||
|
||||
string GetText(int start, int end) |
||||
{ |
||||
if (start == input.Length && end == input.Length) { |
||||
return string.Empty; |
||||
} else { |
||||
return input.Substring(start, end - start); |
||||
} |
||||
} |
||||
|
||||
static char[] WhiteSpaceChars = new char[] {' ', '\n', '\r', '\t'}; |
||||
static char[] WhiteSpaceAndReservedChars = new char[] {' ', '\n', '\r', '\t', '<', '=', '>', '/'}; |
||||
|
||||
bool? IsWhiteSpace() |
||||
{ |
||||
if (currentLocation == input.Length) { |
||||
return null; |
||||
} else { |
||||
return WhiteSpaceChars.Contains(input[currentLocation]); |
||||
} |
||||
} |
||||
|
||||
bool? IsWhiteSpaceOrReserved() |
||||
{ |
||||
if (currentLocation == input.Length) { |
||||
return null; |
||||
} else { |
||||
return WhiteSpaceAndReservedChars.Contains(input[currentLocation]); |
||||
} |
||||
} |
||||
|
||||
string ReadName() |
||||
{ |
||||
Debug.Assert(HasMoreData()); |
||||
|
||||
int start = currentLocation; |
||||
TryMoveTo(WhiteSpaceAndReservedChars.ToArray()); |
||||
return GetText(start, currentLocation); |
||||
} |
||||
|
||||
RawDocument ReadDocument() |
||||
{ |
||||
RawDocument doc = ReadFromCache<RawDocument>(currentLocation); |
||||
if (doc != null) return doc; |
||||
|
||||
doc = new RawDocument(); |
||||
|
||||
doc.StartOffset = currentLocation; |
||||
while(true) { |
||||
if (IsEndOfFile()) { |
||||
break; |
||||
} else if (TryPeek('<')) { |
||||
doc.Children.Add(ReadElement(doc)); |
||||
} else { |
||||
doc.Children.Add(ReadCharacterData(doc)); |
||||
} |
||||
} |
||||
doc.EndOffset = currentLocation; |
||||
|
||||
LogParsed(doc); |
||||
parsedDom.Add(doc); |
||||
return doc; |
||||
} |
||||
|
||||
RawElement ReadElement(RawObject parent) |
||||
{ |
||||
Debug.Assert(HasMoreData() && TryPeek('<')); |
||||
|
||||
RawElement element = ReadFromCache<RawElement>(currentLocation); |
||||
if (element != null) return element; |
||||
|
||||
element = new RawElement() { Parent = parent }; |
||||
|
||||
element.StartOffset = currentLocation; |
||||
element.StartTag = ReadTag(element); |
||||
// Read content
|
||||
if (element.StartTag.ClosingBracket == ">") { |
||||
while(true) { |
||||
if (IsEndOfFile()) { |
||||
break; |
||||
} else if (TryPeek('<')) { |
||||
if (TryPeek("</")) break; |
||||
element.Children.Add(ReadElement(element)); |
||||
} else { |
||||
element.Children.Add(ReadCharacterData(element)); |
||||
} |
||||
} |
||||
} |
||||
// Read closing tag
|
||||
if (TryPeek("</")) { |
||||
element.HasEndTag = true; |
||||
element.EndTag = ReadTag(element); |
||||
} |
||||
element.EndOffset = currentLocation; |
||||
|
||||
LogParsed(element); |
||||
parsedDom.Add(element); |
||||
return element; |
||||
} |
||||
|
||||
RawTag ReadTag(RawObject parent) |
||||
{ |
||||
Debug.Assert(HasMoreData() && TryPeek('<')); |
||||
|
||||
RawTag tag = ReadFromCache<RawTag>(currentLocation); |
||||
if (tag != null) return tag; |
||||
|
||||
tag = new RawTag() { Parent = parent }; |
||||
|
||||
tag.StartOffset = currentLocation; |
||||
if (TryRead('<')) { |
||||
tag.OpeningBracket = "<"; |
||||
if (TryRead('/')) { |
||||
tag.OpeningBracket += "/"; |
||||
} |
||||
} |
||||
if (HasMoreData()) { |
||||
tag.Name = ReadName(); |
||||
} |
||||
// Read attributes
|
||||
while(true) { |
||||
if (IsWhiteSpace() == true) { |
||||
tag.Attributes.Add(ReadWhiteSpace(tag)); |
||||
} |
||||
if (TryRead('>')) { |
||||
tag.ClosingBracket = ">"; |
||||
break; |
||||
} else if (TryRead('/')) { |
||||
tag.ClosingBracket = "/"; |
||||
if (TryRead('>')) { |
||||
tag.ClosingBracket += ">"; |
||||
} |
||||
break; |
||||
} |
||||
if (TryPeek('<')) break; |
||||
if (HasMoreData()) { |
||||
tag.Attributes.Add(ReadAttribulte(tag)); |
||||
continue; |
||||
} |
||||
break; |
||||
} |
||||
tag.EndOffset = currentLocation; |
||||
|
||||
LogParsed(tag); |
||||
parsedDom.Add(tag); |
||||
return tag; |
||||
} |
||||
|
||||
RawText ReadWhiteSpace(RawObject parent) |
||||
{ |
||||
Debug.Assert(HasMoreData() && IsWhiteSpace() == true); |
||||
|
||||
RawText ws = ReadFromCache<RawText>(currentLocation); |
||||
if (ws != null) return ws; |
||||
|
||||
ws = new RawText() { Parent = parent }; |
||||
|
||||
ws.StartOffset = currentLocation; |
||||
int start = currentLocation; |
||||
while(IsWhiteSpace() == true) currentLocation++; |
||||
ws.Value = GetText(start, currentLocation); |
||||
ws.EndOffset = currentLocation; |
||||
|
||||
parsedDom.Add(ws); |
||||
return ws; |
||||
} |
||||
|
||||
RawAttribute ReadAttribulte(RawObject parent) |
||||
{ |
||||
Debug.Assert(HasMoreData()); |
||||
|
||||
RawAttribute attr = ReadFromCache<RawAttribute>(currentLocation); |
||||
if (attr != null) return attr; |
||||
|
||||
attr = new RawAttribute() { Parent = parent }; |
||||
|
||||
attr.StartOffset = currentLocation; |
||||
if (HasMoreData()) { |
||||
attr.Name = ReadName(); |
||||
} |
||||
int checkpoint = currentLocation; |
||||
attr.EqualsSign = string.Empty; |
||||
if (IsWhiteSpace() == true) attr.EqualsSign += ReadWhiteSpace(attr).Value; |
||||
if (TryRead('=')) { |
||||
attr.EqualsSign += "="; |
||||
if (IsWhiteSpace() == true) attr.EqualsSign += ReadWhiteSpace(attr).Value; |
||||
if (IsWhiteSpaceOrReserved() == false) { |
||||
// Read attribute value
|
||||
int start = currentLocation; |
||||
if (TryRead('"')) { |
||||
TryMoveTo('"', '<'); |
||||
TryRead('"'); |
||||
attr.Value = GetText(start, currentLocation); |
||||
} else if (TryRead('\'')) { |
||||
TryMoveTo('\'', '<'); |
||||
TryRead('\''); |
||||
attr.Value = GetText(start, currentLocation); |
||||
} else { |
||||
attr.Value = ReadName(); |
||||
} |
||||
} |
||||
} else { |
||||
attr.EqualsSign = null; |
||||
currentLocation = checkpoint; |
||||
} |
||||
attr.EndOffset = currentLocation; |
||||
|
||||
parsedDom.Add(attr); |
||||
return attr; |
||||
} |
||||
|
||||
RawText ReadCharacterData(RawObject parent) |
||||
{ |
||||
Debug.Assert(HasMoreData()); |
||||
|
||||
RawText charData = ReadFromCache<RawText>(currentLocation); |
||||
if (charData != null) return charData; |
||||
|
||||
charData = new RawText() { Parent = parent }; |
||||
|
||||
charData.StartOffset = currentLocation; |
||||
int start = currentLocation; |
||||
TryMoveTo('<'); |
||||
charData.Value = GetText(start, currentLocation); |
||||
charData.EndOffset = currentLocation; |
||||
|
||||
parsedDom.Add(charData); |
||||
return charData; |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue