##// END OF EJS Templates
JsonXmlReader performance tuning...
cin -
r229:5f7a3e1d32b9 v2
parent child
Show More
@@ -0,0 +1,6
1 <?xml version="1.0" encoding="utf-8" ?>
2 <configuration>
3 <startup>
4 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
5 </startup>
6 </configuration> No newline at end of file
@@ -0,0 +1,68
1 <?xml version="1.0" encoding="utf-8"?>
2 <Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4 <PropertyGroup>
5 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7 <ProjectGuid>{100DFEB0-75BE-436F-ADDF-1F46EF433F46}</ProjectGuid>
8 <OutputType>Exe</OutputType>
9 <AppDesignerFolder>Properties</AppDesignerFolder>
10 <RootNamespace>Implab.Playground</RootNamespace>
11 <AssemblyName>Implab.Playground</AssemblyName>
12 <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
13 <FileAlignment>512</FileAlignment>
14 <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
15 </PropertyGroup>
16 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
17 <PlatformTarget>AnyCPU</PlatformTarget>
18 <DebugSymbols>true</DebugSymbols>
19 <DebugType>full</DebugType>
20 <Optimize>false</Optimize>
21 <OutputPath>bin\Debug\</OutputPath>
22 <DefineConstants>DEBUG;TRACE</DefineConstants>
23 <ErrorReport>prompt</ErrorReport>
24 <WarningLevel>4</WarningLevel>
25 </PropertyGroup>
26 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
27 <PlatformTarget>AnyCPU</PlatformTarget>
28 <DebugType>pdbonly</DebugType>
29 <Optimize>true</Optimize>
30 <OutputPath>bin\Release\</OutputPath>
31 <DefineConstants>TRACE</DefineConstants>
32 <ErrorReport>prompt</ErrorReport>
33 <WarningLevel>4</WarningLevel>
34 <Prefer32Bit>true</Prefer32Bit>
35 <DebugSymbols>true</DebugSymbols>
36 </PropertyGroup>
37 <ItemGroup>
38 <Reference Include="System" />
39 <Reference Include="System.Core" />
40 <Reference Include="System.Xml.Linq" />
41 <Reference Include="System.Data.DataSetExtensions" />
42 <Reference Include="Microsoft.CSharp" />
43 <Reference Include="System.Data" />
44 <Reference Include="System.Net.Http" />
45 <Reference Include="System.Xml" />
46 </ItemGroup>
47 <ItemGroup>
48 <Compile Include="Program.cs" />
49 <Compile Include="Properties\AssemblyInfo.cs" />
50 </ItemGroup>
51 <ItemGroup>
52 <None Include="App.config" />
53 </ItemGroup>
54 <ItemGroup>
55 <ProjectReference Include="..\Implab\Implab.csproj">
56 <Project>{f550f1f8-8746-4ad0-9614-855f4c4b7f05}</Project>
57 <Name>Implab</Name>
58 </ProjectReference>
59 </ItemGroup>
60 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
61 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
62 Other similar extension points exist, see Microsoft.Common.targets.
63 <Target Name="BeforeBuild">
64 </Target>
65 <Target Name="AfterBuild">
66 </Target>
67 -->
68 </Project> No newline at end of file
@@ -0,0 +1,42
1 using Implab.Formats.Json;
2 using Implab.Xml;
3 using System;
4 using System.Collections.Generic;
5 using System.IO;
6 using System.Linq;
7 using System.Text;
8 using System.Threading.Tasks;
9 using System.Xml;
10 using System.Xml.Serialization;
11
12 namespace Implab.Playground {
13 public class Program {
14
15 [XmlRoot(Namespace = "XmlSimpleData")]
16 public class XmlSimpleModel {
17 [XmlElement]
18 public string Name { get; set; }
19
20 [XmlElement]
21 public int Order { get; set; }
22
23 [XmlElement]
24 public string[] Items { get; set; }
25
26 }
27
28 static void Main(string[] args) {
29 var model = new XmlSimpleModel {
30 Name = "Tablet",
31 Order = 10,
32 Items = new string[] { "z1", "z2", "z3" }
33 };
34
35 var doc = SerializationHelpers.SerializeAsXmlDocument(model);
36
37 var m2 = SerializationHelpers.DeserializeFromXmlNode<XmlSimpleModel>(doc.DocumentElement);
38
39 Console.WriteLine("done");
40 }
41 }
42 }
@@ -0,0 +1,36
1 using System.Reflection;
2 using System.Runtime.CompilerServices;
3 using System.Runtime.InteropServices;
4
5 // General Information about an assembly is controlled through the following
6 // set of attributes. Change these attribute values to modify the information
7 // associated with an assembly.
8 [assembly: AssemblyTitle("Implab.Playground")]
9 [assembly: AssemblyDescription("")]
10 [assembly: AssemblyConfiguration("")]
11 [assembly: AssemblyCompany("")]
12 [assembly: AssemblyProduct("Implab.Playground")]
13 [assembly: AssemblyCopyright("Copyright © 2017")]
14 [assembly: AssemblyTrademark("")]
15 [assembly: AssemblyCulture("")]
16
17 // Setting ComVisible to false makes the types in this assembly not visible
18 // to COM components. If you need to access a type in this assembly from
19 // COM, set the ComVisible attribute to true on that type.
20 [assembly: ComVisible(false)]
21
22 // The following GUID is for the ID of the typelib if this project is exposed to COM
23 [assembly: Guid("100dfeb0-75be-436f-addf-1f46ef433f46")]
24
25 // Version information for an assembly consists of the following four values:
26 //
27 // Major Version
28 // Minor Version
29 // Build Number
30 // Revision
31 //
32 // You can specify all the values or you can default the Build and Revision Numbers
33 // by using the '*' as shown below:
34 // [assembly: AssemblyVersion("1.0.*")]
35 [assembly: AssemblyVersion("1.0.0.0")]
36 [assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,75
1 <?xml version="1.0" encoding="UTF-8"?>
2 <VSPerformanceSession Version="1.00">
3 <Options>
4 <Solution>Implab.sln</Solution>
5 <CollectionMethod>Sampling</CollectionMethod>
6 <AllocationMethod>None</AllocationMethod>
7 <AddReport>true</AddReport>
8 <ResourceBasedAnalysisSelected>true</ResourceBasedAnalysisSelected>
9 <UniqueReport>Timestamp</UniqueReport>
10 <SamplingMethod>Cycles</SamplingMethod>
11 <CycleCount>50000</CycleCount>
12 <PageFaultCount>10</PageFaultCount>
13 <SysCallCount>10</SysCallCount>
14 <SamplingCounter Name="" ReloadValue="00000000000f4240" DisplayName="" />
15 <RelocateBinaries>false</RelocateBinaries>
16 <HardwareCounters EnableHWCounters="false" />
17 <EtwSettings />
18 <PdhSettings>
19 <PdhCountersEnabled>false</PdhCountersEnabled>
20 <PdhCountersRate>500</PdhCountersRate>
21 <PdhCounters>
22 <PdhCounter>\Память\Обмен страниц/с</PdhCounter>
23 <PdhCounter>\Процессор(_Total)\% загруженности процессора</PdhCounter>
24 <PdhCounter>\Физический диск(_Total)\Средняя длина очереди диска</PdhCounter>
25 </PdhCounters>
26 </PdhSettings>
27 </Options>
28 <ExcludeSmallFuncs>true</ExcludeSmallFuncs>
29 <InteractionProfilingEnabled>false</InteractionProfilingEnabled>
30 <JScriptProfilingEnabled>false</JScriptProfilingEnabled>
31 <PreinstrumentEvent>
32 <InstrEventExclude>false</InstrEventExclude>
33 </PreinstrumentEvent>
34 <PostinstrumentEvent>
35 <InstrEventExclude>false</InstrEventExclude>
36 </PostinstrumentEvent>
37 <Binaries>
38 <ProjBinary>
39 <Path>Implab.Playground\obj\Debug\Implab.Playground.exe</Path>
40 <ArgumentTimestamp>01/01/0001 00:00:00</ArgumentTimestamp>
41 <Instrument>true</Instrument>
42 <Sample>true</Sample>
43 <ExternalWebsite>false</ExternalWebsite>
44 <InteractionProfilingEnabled>false</InteractionProfilingEnabled>
45 <IsLocalJavascript>false</IsLocalJavascript>
46 <IsWindowsStoreApp>false</IsWindowsStoreApp>
47 <IsWWA>false</IsWWA>
48 <LaunchProject>true</LaunchProject>
49 <OverrideProjectSettings>false</OverrideProjectSettings>
50 <LaunchMethod>Executable</LaunchMethod>
51 <ExecutablePath>Implab.Playground\bin\Release\Implab.Playground.exe</ExecutablePath>
52 <StartupDirectory>Implab.Playground\bin\Release\</StartupDirectory>
53 <Arguments>
54 </Arguments>
55 <NetAppHost>IIS</NetAppHost>
56 <NetBrowser>InternetExplorer</NetBrowser>
57 <ExcludeSmallFuncs>true</ExcludeSmallFuncs>
58 <JScriptProfilingEnabled>false</JScriptProfilingEnabled>
59 <PreinstrumentEvent>
60 <InstrEventExclude>false</InstrEventExclude>
61 </PreinstrumentEvent>
62 <PostinstrumentEvent>
63 <InstrEventExclude>false</InstrEventExclude>
64 </PostinstrumentEvent>
65 <ProjRef>{100DFEB0-75BE-436F-ADDF-1F46EF433F46}|Implab.Playground\Implab.Playground.csproj</ProjRef>
66 <ProjPath>Implab.Playground\Implab.Playground.csproj</ProjPath>
67 <ProjName>Implab.Playground</ProjName>
68 </ProjBinary>
69 </Binaries>
70 <Launches>
71 <ProjBinary>
72 <Path>:PB:{100DFEB0-75BE-436F-ADDF-1F46EF433F46}|Implab.Playground\Implab.Playground.csproj</Path>
73 </ProjBinary>
74 </Launches>
75 </VSPerformanceSession> No newline at end of file
@@ -0,0 +1,45
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6 using System.Xml;
7 using System.Xml.Linq;
8
9 namespace Implab.Xml {
10 public static class SerializationHelpers {
11 public static string SerializeAsString<T>(T obj) {
12 return SerializersPool<T>.Instance.SerializeAsString(obj);
13 }
14
15 public static void Serialize<T>(XmlWriter writer, T obj) {
16 SerializersPool<T>.Instance.Serialize(writer, obj);
17 }
18
19 public static XmlDocument SerializeAsXmlDocument<T>(T obj) {
20 var doc = new XmlDocument();
21 using (var writer = doc.CreateNavigator().AppendChild()) {
22 SerializersPool<T>.Instance.Serialize(writer, obj);
23 }
24 return doc;
25 }
26
27 public static XDocument SerializeAsXDocument<T>(T obj) {
28 var doc = new XDocument();
29 using (var writer = doc.CreateWriter()) {
30 SerializersPool<T>.Instance.Serialize(writer, obj);
31 }
32 return doc;
33 }
34
35 public static T DeserializeFromString<T>(string data) {
36 return SerializersPool<T>.Instance.DeserializeFromString(data);
37 }
38
39 public static T DeserializeFromXmlNode<T>(XmlNode node) {
40 Safe.ArgumentNotNull(node, nameof(node));
41 using (var reader = node.CreateNavigator().ReadSubtree())
42 return SerializersPool<T>.Instance.Deserialize(reader);
43 }
44 }
45 }
@@ -0,0 +1,76
1 using Implab.Components;
2 using System;
3 using System.Collections.Generic;
4 using System.IO;
5 using System.Linq;
6 using System.Text;
7 using System.Threading.Tasks;
8 using System.Xml;
9 using System.Xml.Serialization;
10
11 namespace Implab.Xml {
12 public class SerializersPool<T> : ObjectPool<XmlSerializer> {
13
14 static readonly SerializersPool<T> _instance = new SerializersPool<T>();
15
16 public static SerializersPool<T> Instance {
17 get { return _instance; }
18 }
19
20 #region implemented abstract members of ObjectPool
21 protected override XmlSerializer CreateInstance() {
22 return new XmlSerializer(typeof(T));
23 }
24 #endregion
25
26 public T DeserializeFromString(string data) {
27 using (var reader = new StringReader(data)) {
28 return Deserialize(reader);
29 }
30 }
31
32 public T Deserialize(TextReader reader) {
33 var sr = Allocate();
34 try {
35 return (T)sr.Deserialize(reader);
36 } finally {
37 Release(sr);
38 }
39 }
40
41 public T Deserialize(XmlReader reader) {
42 var sr = Allocate();
43 try {
44 return (T)sr.Deserialize(reader);
45 } finally {
46 Release(sr);
47 }
48 }
49
50 public string SerializeAsString(T data) {
51 using (var writer = new StringWriter()) {
52 Serialize(writer, data);
53 return writer.ToString();
54 }
55 }
56
57 public void Serialize(TextWriter writer, T data) {
58 var sr = Allocate();
59 try {
60 sr.Serialize(writer, data);
61 } finally {
62 Release(sr);
63 }
64 }
65
66 public void Serialize(XmlWriter writer, T data) {
67 var sr = Allocate();
68 try {
69 sr.Serialize(writer, data);
70 } finally {
71 Release(sr);
72 }
73 }
74
75 }
76 }
@@ -21,3 +21,5 Implab.Test/Implab.Format.Test/obj/
21 21 Implab.Format.Test/bin/
22 22 Implab.Format.Test/obj/
23 23 packages/
24 Implab.Playground/obj/
25 Implab.Playground/bin/
@@ -5,6 +5,7 using Implab.Xml;
5 5 using System.Xml;
6 6 using Implab.Formats;
7 7 using Implab.Formats.Json;
8 using System.IO;
8 9
9 10 namespace Implab.Format.Test {
10 11 [TestFixture]
@@ -15,19 +16,19 namespace Implab.Format.Test {
15 16 using (var scanner = JsonStringScanner.Create(@"9123, -123, 0, 0.1, -0.2, -0.1e3, 1.3E-3, ""some \t\n\u0020 text"", literal []{}:")) {
16 17
17 18 Tuple<JsonTokenType, object>[] expexted = {
18 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 9123d),
19 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "9123"),
19 20 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
20 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -123d),
21 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "-123"),
21 22 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
22 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0d),
23 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "0"),
23 24 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
24 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0.1d),
25 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "0.1"),
25 26 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
26 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.2d),
27 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "-0.2"),
27 28 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
28 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.1e3d),
29 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "-0.1e3"),
29 30 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
30 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 1.3E-3d),
31 new Tuple<JsonTokenType,object>(JsonTokenType.Number, "1.3E-3"),
31 32 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
32 33 new Tuple<JsonTokenType,object>(JsonTokenType.String, "some \t\n text"),
33 34 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
@@ -39,7 +40,7 namespace Implab.Format.Test {
39 40 new Tuple<JsonTokenType,object>(JsonTokenType.NameSeparator, null)
40 41 };
41 42
42 object value;
43 string value;
43 44 JsonTokenType tokenType;
44 45 for (var i = 0; i < expexted.Length; i++) {
45 46
@@ -73,7 +74,7 namespace Implab.Format.Test {
73 74 foreach (var json in bad) {
74 75 using (var scanner = JsonStringScanner.Create(json)) {
75 76 try {
76 object value;
77 string value;
77 78 JsonTokenType token;
78 79 scanner.ReadToken(out value, out token);
79 80 if (!Object.Equals(value, json)) {
@@ -109,11 +110,11 namespace Implab.Format.Test {
109 110 //DumpJsonParse("{}");
110 111 //DumpJsonParse("[]");
111 112 DumpJsonParse("{\"one\":1, \"two\":2}");
112 DumpJsonParse("[1,2,3]");
113 DumpJsonParse("[1,\"\",2,3]");
113 114 DumpJsonParse("[{\"info\": [7,8,9]}]");
114 DumpJsonFlatParse("[1,2,[3,4],{\"info\": [5,6]},{\"num\": [7,8,null]}, null,[null]]");
115 DumpJsonFlatParse("[1,2,\"\",[3,4],{\"info\": [5,6]},{\"num\": [7,8,null]}, null,[null]]");
115 116 }
116
117
117 118 void AssertRead(XmlReader reader, XmlNodeType expected) {
118 119 Assert.IsTrue(reader.Read());
119 120 Console.WriteLine($"{new string(' ', reader.Depth*2)}{reader}");
@@ -123,7 +124,7 namespace Implab.Format.Test {
123 124 void DumpJsonParse(string json) {
124 125 Console.WriteLine($"JSON: {json}");
125 126 Console.WriteLine("XML");
126 using (var xmlReader = new JsonXmlReader(new JsonParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "json" })) {
127 using (var xmlReader = new JsonXmlReader(JsonReader.ParseString(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "json" })) {
127 128 while (xmlReader.Read())
128 129 Console.WriteLine($"{new string(' ', xmlReader.Depth * 2)}{xmlReader}");
129 130 }
@@ -137,7 +138,7 namespace Implab.Format.Test {
137 138 CloseOutput = false,
138 139 ConformanceLevel = ConformanceLevel.Document
139 140 }))
140 using (var xmlReader = new JsonXmlReader(new JsonParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "", FlattenArrays = true })) {
141 using (var xmlReader = new JsonXmlReader(JsonReader.ParseString(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "", FlattenArrays = true })) {
141 142 xmlWriter.WriteNode(xmlReader, false);
142 143 }
143 144 }
@@ -16,11 +16,14 Project("{FAE04EC0-301F-11D3-BF4B-00C04F
16 16 EndProject
17 17 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Fx", "Implab.Fx\Implab.Fx.csproj", "{06E706F8-6881-43EB-927E-FFC503AF6ABC}"
18 18 EndProject
19 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Fx.Test", "Implab.Fx.Test\Implab.Fx.Test.csproj", "{2F31E405-E267-4195-A05D-574093C21209}"
20 EndProject
21 19 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Format.Test", "Implab.Format.Test\Implab.Format.Test.csproj", "{4D364996-7ECD-4193-8F90-F223FFEA49DA}"
22 20 EndProject
21 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Playground", "Implab.Playground\Implab.Playground.csproj", "{100DFEB0-75BE-436F-ADDF-1F46EF433F46}"
22 EndProject
23 23 Global
24 GlobalSection(Performance) = preSolution
25 HasPerformanceSessions = true
26 EndGlobalSection
24 27 GlobalSection(SolutionConfigurationPlatforms) = preSolution
25 28 Debug 4.5|Any CPU = Debug 4.5|Any CPU
26 29 Debug|Any CPU = Debug|Any CPU
@@ -52,14 +55,6 Global
52 55 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
53 56 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release|Any CPU.ActiveCfg = Release|Any CPU
54 57 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release|Any CPU.Build.0 = Release|Any CPU
55 {2F31E405-E267-4195-A05D-574093C21209}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
56 {2F31E405-E267-4195-A05D-574093C21209}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
57 {2F31E405-E267-4195-A05D-574093C21209}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
58 {2F31E405-E267-4195-A05D-574093C21209}.Debug|Any CPU.Build.0 = Debug|Any CPU
59 {2F31E405-E267-4195-A05D-574093C21209}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
60 {2F31E405-E267-4195-A05D-574093C21209}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
61 {2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.ActiveCfg = Release|Any CPU
62 {2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.Build.0 = Release|Any CPU
63 58 {4D364996-7ECD-4193-8F90-F223FFEA49DA}.Debug 4.5|Any CPU.ActiveCfg = Debug|Any CPU
64 59 {4D364996-7ECD-4193-8F90-F223FFEA49DA}.Debug 4.5|Any CPU.Build.0 = Debug|Any CPU
65 60 {4D364996-7ECD-4193-8F90-F223FFEA49DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@@ -68,6 +63,14 Global
68 63 {4D364996-7ECD-4193-8F90-F223FFEA49DA}.Release 4.5|Any CPU.Build.0 = Release|Any CPU
69 64 {4D364996-7ECD-4193-8F90-F223FFEA49DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
70 65 {4D364996-7ECD-4193-8F90-F223FFEA49DA}.Release|Any CPU.Build.0 = Release|Any CPU
66 {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Debug 4.5|Any CPU.ActiveCfg = Debug|Any CPU
67 {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Debug 4.5|Any CPU.Build.0 = Debug|Any CPU
68 {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
69 {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Debug|Any CPU.Build.0 = Debug|Any CPU
70 {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Release 4.5|Any CPU.ActiveCfg = Release|Any CPU
71 {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Release 4.5|Any CPU.Build.0 = Release|Any CPU
72 {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Release|Any CPU.ActiveCfg = Release|Any CPU
73 {100DFEB0-75BE-436F-ADDF-1F46EF433F46}.Release|Any CPU.Build.0 = Release|Any CPU
71 74 EndGlobalSection
72 75 GlobalSection(SolutionProperties) = preSolution
73 76 HideSolutionNode = FALSE
@@ -119,7 +119,7 namespace Implab.Automaton {
119 119 table[i, j] = AutomatonConst.UNREACHABLE_STATE;
120 120
121 121 foreach (var t in this)
122 table[t.s1,t.edge] = t.s2;
122 table[t.s1,t.edge] = (byte)t.s2;
123 123
124 124 return table;
125 125 }
@@ -2,6 +2,7
2 2 using System;
3 3 using System.Collections.Generic;
4 4 using System.Linq;
5 using System.Runtime.CompilerServices;
5 6 using System.Text;
6 7 using System.Threading.Tasks;
7 8
@@ -30,24 +31,28 namespace Implab.Formats {
30 31 }
31 32
32 33 public TTag Tag {
34 [MethodImpl(MethodImplOptions.AggressiveInlining)]
33 35 get {
34 36 return m_tags[m_state];
35 37 }
36 38 }
37 39
38 40 public int Position {
41 [MethodImpl(MethodImplOptions.AggressiveInlining)]
39 42 get {
40 43 return m_position;
41 44 }
42 45 }
43 46
44 47 public bool IsFinal {
48 [MethodImpl(MethodImplOptions.AggressiveInlining)]
45 49 get {
46 50 return m_final[m_state];
47 51 }
48 52 }
49 53
50 public void Reset() {
54 [MethodImpl(MethodImplOptions.AggressiveInlining)]
55 public void ResetState() {
51 56 m_state = m_initialState;
52 57 }
53 58
@@ -58,13 +63,8 namespace Implab.Formats {
58 63 return clone;
59 64 }
60 65
61 public bool Scan(char[] data, int offset, int length) {
62 if (length <= 0) {
63 m_position = offset;
64 return false; // EOF
65 }
66
67 var max = offset + length;
66 //[MethodImpl(MethodImplOptions.AggressiveInlining)]
67 public bool Scan(char[] data, int offset, int max) {
68 68 var next = m_state;
69 69
70 70 while(offset < max) {
@@ -6,6 +6,8 using Implab.Automaton.RegularExpression
6 6 using System.Linq;
7 7 using Implab.Components;
8 8 using System.Collections.Generic;
9 using System.Text;
10 using System.Globalization;
9 11
10 12 namespace Implab.Formats.Json {
11 13 /// <summary>
@@ -24,7 +26,7 namespace Implab.Formats.Json {
24 26 /// } // Level = 0
25 27 /// </code>
26 28 /// </remarks>
27 public class JsonParser : Disposable {
29 public class JsonReader : Disposable {
28 30
29 31 enum MemberContext {
30 32 MemberName,
@@ -61,7 +63,7 namespace Implab.Formats.Json {
61 63 static readonly ParserContext _objectContext;
62 64 static readonly ParserContext _arrayContext;
63 65
64 static JsonParser() {
66 static JsonReader() {
65 67
66 68 var valueExpression = MakeToken(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String);
67 69 var memberExpression = MakeToken(JsonTokenType.String).Cat(MakeToken(JsonTokenType.NameSeparator)).Cat(valueExpression);
@@ -124,20 +126,10 namespace Implab.Formats.Json {
124 126 /// Создает новый парсер на основе строки, содержащей JSON
125 127 /// </summary>
126 128 /// <param name="text"></param>
127 public JsonParser(string text) {
128 Safe.ArgumentNotEmpty(text, "text");
129 m_scanner = JsonStringScanner.Create(text);
129 JsonReader(JsonScanner scanner) {
130 m_scanner = scanner;
130 131 }
131
132 /// <summary>
133 /// Создает новый экземпляр парсера, на основе текстового потока.
134 /// </summary>
135 /// <param name="reader">Текстовый поток.</param>
136 public JsonParser(TextReader reader) {
137 Safe.ArgumentNotNull(reader, "reader");
138 m_scanner = JsonTextScanner.Create(reader);
139 }
140
132
141 133 public int Level {
142 134 get { return m_stack.Count; }
143 135 }
@@ -169,7 +161,7 namespace Implab.Formats.Json {
169 161 /// </summary>
170 162 /// <returns><c>true</c> - операция чтения прошла успешно, <c>false</c> - конец данных</returns>
171 163 public bool Read() {
172 object tokenValue;
164 string tokenValue;
173 165 JsonTokenType tokenType;
174 166
175 167 m_memberName = String.Empty;
@@ -213,7 +205,7 namespace Implab.Formats.Json {
213 205 return true;
214 206 case JsonTokenType.String:
215 207 if (m_memberContext == MemberContext.MemberName) {
216 m_memberName = (string)tokenValue;
208 m_memberName = tokenValue;
217 209 break;
218 210 }
219 211 m_elementType = JsonElementType.Value;
@@ -221,11 +213,11 namespace Implab.Formats.Json {
221 213 return true;
222 214 case JsonTokenType.Number:
223 215 m_elementType = JsonElementType.Value;
224 m_elementValue = tokenValue;
216 m_elementValue = double.Parse(tokenValue, CultureInfo.InvariantCulture);
225 217 return true;
226 218 case JsonTokenType.Literal:
227 219 m_elementType = JsonElementType.Value;
228 m_elementValue = ParseLiteral((string)tokenValue);
220 m_elementValue = ParseLiteral(tokenValue);
229 221 return true;
230 222 case JsonTokenType.NameSeparator:
231 223 m_memberContext = MemberContext.MemberValue;
@@ -241,7 +233,7 namespace Implab.Formats.Json {
241 233 if (m_context.ElementContext != JsonElementContext.None)
242 234 throw new ParserException("Unexpedted end of data");
243 235
244 EOF = true;
236 Eof = true;
245 237
246 238 return false;
247 239 }
@@ -268,7 +260,7 namespace Implab.Formats.Json {
268 260 /// <summary>
269 261 /// Признак конца потока
270 262 /// </summary>
271 public bool EOF {
263 public bool Eof {
272 264 get;
273 265 private set;
274 266 }
@@ -289,6 +281,38 namespace Implab.Formats.Json {
289 281 while (Level != level)
290 282 Read();
291 283 }
284
285 public static JsonReader Create(string file, Encoding encoding) {
286 return new JsonReader(JsonTextScanner.Create(file, encoding));
287 }
288
289 public static JsonReader Create(string file) {
290 return new JsonReader(JsonTextScanner.Create(file));
291 }
292
293 public static JsonReader Create(Stream stream, Encoding encoding) {
294 return new JsonReader(JsonTextScanner.Create(stream, encoding));
295 }
296
297 public static JsonReader Create(Stream stream) {
298 return new JsonReader(JsonTextScanner.Create(stream));
299 }
300
301 public static JsonReader Create(TextReader reader) {
302 return new JsonReader(JsonTextScanner.Create(reader));
303 }
304
305 public static JsonReader ParseString(string data) {
306 return new JsonReader(JsonStringScanner.Create(data));
307 }
308
309 public static JsonReader ParseString(string data, int offset, int length) {
310 return new JsonReader(JsonStringScanner.Create(data, offset, length));
311 }
312
313 public static JsonReader ParseString(char[] data, int offset, int lenght) {
314 return new JsonReader(JsonStringScanner.Create(data, offset, lenght));
315 }
292 316 }
293 317
294 318 }
@@ -25,38 +25,94 namespace Implab.Formats.Json {
25 25 m_length = length;
26 26 }
27 27
28 bool Read(InputScanner<JsonGrammar.TokenType> scanner, out JsonGrammar.TokenType tokenType) {
29 scanner.Reset();
28 bool ReadChunk(InputScanner<JsonGrammar.TokenType> scanner, out JsonGrammar.TokenType tokenType) {
29 scanner.ResetState();
30
31 while(scanner.Scan(m_buffer, m_pos, m_length)) {
32 // scanner requests new data
30 33
31 if (m_pos == m_length) {
32 m_pos = 0;
34 if (m_pos != m_length) // capture results for the future
35 m_tokenBuilder.Append(m_buffer, m_pos, m_length - m_pos);
36
37 // read next data
33 38 m_length = Read(m_buffer, 0, m_buffer.Length);
39
34 40 if (m_length == 0) {
35 tokenType = JsonGrammar.TokenType.None;
36 return false; // EOF
41 // no data is read
42 if (scanner.Position == m_pos) {
43 // scanned hasn't moved, that's the end
44 m_pos = 0;
45 tokenType = JsonGrammar.TokenType.None;
46 return false;
47 }
48
49 if (scanner.IsFinal) {
50 m_pos = 0;
51 tokenType = scanner.Tag;
52 return true;
53 } else {
54 throw new ParserException("Unexpected EOF");
55 }
37 56 }
38 }
39
40 while(scanner.Scan(m_buffer, m_pos, m_length - m_pos)) {
41 m_tokenBuilder.Append(m_buffer, m_pos, m_length - m_pos);
57
42 58 m_pos = 0;
43 m_length = Read(m_buffer, 0, m_buffer.Length);
44 59 }
45 60 var scannerPos = scanner.Position;
61
62 // scanner stops as scannerPos
63 if (!scanner.IsFinal)
64 throw new ParserException($"Unexpected character '{m_buffer[scannerPos + 1]}'");
65
66 tokenType = scanner.Tag;
67 if (scannerPos != m_pos && tokenType == JsonGrammar.TokenType.Number || tokenType == JsonGrammar.TokenType.Literal)
68 m_tokenBuilder.Append(m_buffer, m_pos, scannerPos - m_pos);
69
70 m_pos = scannerPos;
71 return true;
72 }
73
74 bool ReadStringChunk(InputScanner<JsonGrammar.TokenType> scanner, out JsonGrammar.TokenType tokenType) {
75 scanner.ResetState();
76
77 while (scanner.Scan(m_buffer, m_pos, m_length)) {
78 // scanner requests new data
79
80 if (m_pos != m_length) // capture results for the future
81 m_tokenBuilder.Append(m_buffer, m_pos, m_length - m_pos);
82
83 // read next data
84 m_length = Read(m_buffer, 0, m_buffer.Length);
85
86 if (m_length == 0) {
87 // no data is read
88 if (scanner.Position == m_pos) {
89 // scanned hasn't moved, that's the end
90 m_pos = 0;
91 tokenType = JsonGrammar.TokenType.None;
92 return false;
93 }
94
95 if (scanner.IsFinal) {
96 m_pos = 0;
97 tokenType = scanner.Tag;
98 return true;
99 } else {
100 throw new ParserException("Unexpected EOF");
101 }
102 }
103
104 m_pos = 0;
105 }
106 var scannerPos = scanner.Position;
107
108 // scanner stops as scannerPos
109 if (!scanner.IsFinal)
110 throw new ParserException($"Unexpected character '{m_buffer[scannerPos + 1]}'");
111
46 112 if (scannerPos != m_pos) {
47 113 m_tokenBuilder.Append(m_buffer, m_pos, scannerPos - m_pos);
48 114 m_pos = scannerPos;
49 115 }
50
51 if (!scanner.IsFinal) {
52 if (m_length == 0) {
53 // unexpected EOF
54 throw new ParserException("Unexpected EOF");
55 } else {
56 // unecpected character
57 throw new ParserException($"Unexpected character '{m_buffer[m_pos + 1]}'");
58 }
59 }
60 116 tokenType = scanner.Tag;
61 117 return true;
62 118 }
@@ -72,17 +128,17 namespace Implab.Formats.Json {
72 128 /// <returns><c>true</c> - чтение произведено успешно. <c>false</c> - достигнут конец входных данных</returns>
73 129 /// <remarks>В случе если токен не распознается, возникает исключение. Значения токенов обрабатываются, т.е.
74 130 /// в строках обрабатываются экранированные символы, числа становтся типа double.</remarks>
75 public bool ReadToken(out object tokenValue, out JsonTokenType tokenType) {
131 public bool ReadToken(out string tokenValue, out JsonTokenType tokenType) {
76 132 JsonGrammar.TokenType tag;
77 133 m_tokenBuilder.Clear();
78 while (Read(m_jsonContext, out tag)) {
134 while (ReadChunk(m_jsonContext, out tag)) {
79 135 switch (tag) {
80 136 case JsonGrammar.TokenType.StringBound:
81 137 tokenValue = ReadString();
82 138 tokenType = JsonTokenType.String;
83 139 break;
84 140 case JsonGrammar.TokenType.Number:
85 tokenValue = Double.Parse(m_tokenBuilder.ToString(), CultureInfo.InvariantCulture);
141 tokenValue = m_tokenBuilder.ToString();
86 142 tokenType = JsonTokenType.Number;
87 143 break;
88 144 case JsonGrammar.TokenType.Literal:
@@ -108,7 +164,7 namespace Implab.Formats.Json {
108 164 JsonGrammar.TokenType tag;
109 165 m_tokenBuilder.Clear();
110 166
111 while (Read(m_stringContext, out tag)) {
167 while (ReadStringChunk(m_stringContext, out tag)) {
112 168 switch (tag) {
113 169 case JsonGrammar.TokenType.StringBound:
114 170 m_tokenBuilder.Length--;
@@ -7,7 +7,7 using System.Threading.Tasks;
7 7
8 8 namespace Implab.Formats.Json {
9 9 public class JsonTextScanner : JsonScanner {
10 const int _bufferSize = 4096;
10 const int _bufferSize = 16*4096;
11 11 readonly TextReader m_reader;
12 12
13 13 JsonTextScanner(TextReader reader, char[] buffer) : base(buffer, 0, 0) {
@@ -70,6 +70,7
70 70 <Reference Include="System" />
71 71 <Reference Include="System.Xml" />
72 72 <Reference Include="mscorlib" />
73 <Reference Include="System.Xml.Linq" />
73 74 </ItemGroup>
74 75 <ItemGroup>
75 76 <Compile Include="Components\StateChangeEventArgs.cs" />
@@ -171,7 +172,7
171 172 <Compile Include="Formats\Json\JsonElementContext.cs" />
172 173 <Compile Include="Formats\Json\JsonElementType.cs" />
173 174 <Compile Include="Formats\Json\JsonGrammar.cs" />
174 <Compile Include="Formats\Json\JsonParser.cs" />
175 <Compile Include="Formats\Json\JsonReader.cs" />
175 176 <Compile Include="Formats\Json\JsonScanner.cs" />
176 177 <Compile Include="Formats\Json\JsonTokenType.cs" />
177 178 <Compile Include="Formats\Json\JsonWriter.cs" />
@@ -199,6 +200,8
199 200 <Compile Include="Xml\JsonXmlReader.cs" />
200 201 <Compile Include="Xml\JsonXmlReaderOptions.cs" />
201 202 <Compile Include="Xml\JsonXmlReaderPosition.cs" />
203 <Compile Include="Xml\SerializationHelpers.cs" />
204 <Compile Include="Xml\SerializersPool.cs" />
202 205 <Compile Include="Xml\XmlSimpleAttribute.cs" />
203 206 <Compile Include="Xml\XmlNameContext.cs" />
204 207 </ItemGroup>
@@ -12,7 +12,7 namespace Implab.Xml {
12 12 public bool skip;
13 13 }
14 14
15 JsonParser m_parser;
15 JsonReader m_parser;
16 16 JsonXmlReaderOptions m_options;
17 17 JsonXmlReaderPosition m_position = JsonXmlReaderPosition.Initial;
18 18 XmlNameTable m_nameTable;
@@ -57,7 +57,7 namespace Implab.Xml {
57 57 readonly string m_xsiNamespace;
58 58
59 59
60 public JsonXmlReader(JsonParser parser, JsonXmlReaderOptions options) {
60 public JsonXmlReader(JsonReader parser, JsonXmlReaderOptions options) {
61 61 Safe.ArgumentNotNull(parser, nameof(parser));
62 62 m_parser = parser;
63 63
@@ -77,7 +77,7 namespace Implab.Xml {
77 77
78 78 // TODO validate m_jsonRootName, m_jsonArrayItemName
79 79
80 m_context = new XmlNameContext(null);
80 m_context = new XmlNameContext(null, 0);
81 81 }
82 82
83 83 public override int AttributeCount {
@@ -314,22 +314,6 namespace Implab.Xml {
314 314 case XmlNodeType.Element:
315 315 // if the elemnt is empty the next element will be it's sibling
316 316 return m_isEmpty;
317
318 case XmlNodeType.Document:
319 case XmlNodeType.DocumentFragment:
320 case XmlNodeType.Entity:
321 case XmlNodeType.Text:
322 case XmlNodeType.CDATA:
323 case XmlNodeType.EntityReference:
324 case XmlNodeType.ProcessingInstruction:
325 case XmlNodeType.Comment:
326 case XmlNodeType.DocumentType:
327 case XmlNodeType.Notation:
328 case XmlNodeType.Whitespace:
329 case XmlNodeType.SignificantWhitespace:
330 case XmlNodeType.EndElement:
331 case XmlNodeType.EndEntity:
332 case XmlNodeType.XmlDeclaration:
333 317 default:
334 318 return true;
335 319 }
@@ -351,25 +335,29 namespace Implab.Xml {
351 335 if (!IsSibling()) // the node is nested
352 336 m_xmlDepth++;
353 337
354 m_context = new XmlNameContext(m_context);
338 var context = m_context;
355 339 List<XmlSimpleAttribute> definedAttrs = null;
356 340
357 341 // define new namespaces
358 342 if (attrs != null) {
359 343 foreach (var attr in attrs) {
360 344 if (attr.QName.Name == "xmlns") {
361 m_context.DefinePrefix(ConvertValueToString(attr.Value), string.Empty);
345 if (context == m_context)
346 context = new XmlNameContext(m_context, m_xmlDepth);
347 context.DefinePrefix(ConvertValueToString(attr.Value), string.Empty);
362 348 } else if (attr.Prefix == m_xmlnsPrefix) {
363 m_context.DefinePrefix(ConvertValueToString(attr.Value), attr.QName.Name);
349 if (context == m_context)
350 context = new XmlNameContext(m_context, m_xmlDepth);
351 context.DefinePrefix(ConvertValueToString(attr.Value), attr.QName.Name);
364 352 } else {
365 353 string attrPrefix;
366 354 if (string.IsNullOrEmpty(attr.QName.Namespace))
367 355 continue;
368 356
369 357 // auto-define prefixes
370 if (!m_context.LookupNamespacePrefix(attr.QName.Namespace, out attrPrefix) || string.IsNullOrEmpty(attrPrefix)) {
358 if (!context.LookupNamespacePrefix(attr.QName.Namespace, out attrPrefix) || string.IsNullOrEmpty(attrPrefix)) {
371 359 // new namespace prefix added
372 attrPrefix = m_context.CreateNamespacePrefix(attr.QName.Namespace);
360 attrPrefix = context.CreateNamespacePrefix(attr.QName.Namespace);
373 361 attr.Prefix = attrPrefix;
374 362
375 363 if (definedAttrs == null)
@@ -383,8 +371,10 namespace Implab.Xml {
383 371
384 372 string p;
385 373 // auto-define prefixes
386 if (!m_context.LookupNamespacePrefix(ns, out p)) {
387 p = m_context.CreateNamespacePrefix(ns);
374 if (!context.LookupNamespacePrefix(ns, out p)) {
375 if (context == m_context)
376 context = new XmlNameContext(m_context, m_xmlDepth);
377 p = context.CreateNamespacePrefix(ns);
388 378 if (definedAttrs == null)
389 379 definedAttrs = new List<XmlSimpleAttribute>();
390 380
@@ -397,6 +387,9 namespace Implab.Xml {
397 387 attrs = definedAttrs.ToArray();
398 388 }
399 389
390 if (!empty)
391 m_context = context;
392
400 393 m_nodeType = XmlNodeType.Element;
401 394 m_qName = new XmlQualifiedName(name, ns);
402 395 m_prefix = p;
@@ -406,14 +399,18 namespace Implab.Xml {
406 399 }
407 400
408 401 void EndElementNode(string name, string ns) {
409 if (IsSibling()) // closing the element which has children
402 if (IsSibling()) {
403 // closing the element which has children
410 404 m_xmlDepth--;
405 }
411 406
412 407 string p;
413 408 if (!m_context.LookupNamespacePrefix(ns, out p))
414 409 throw new Exception($"Failed to lookup namespace '{ns}'");
415 410
416 m_context = m_context.ParentContext;
411 if (m_context.Depth == m_xmlDepth)
412 m_context = m_context.ParentContext;
413
417 414 m_nodeType = XmlNodeType.EndElement;
418 415 m_prefix = p;
419 416 m_qName = new XmlQualifiedName(name, ns);
@@ -456,7 +453,10 namespace Implab.Xml {
456 453 break;
457 454 case JsonXmlReaderPosition.ValueElement:
458 455 if (!m_isEmpty) {
459 ValueNode(m_parser.ElementValue);
456 if (m_parser.ElementValue != null && !m_parser.ElementValue.Equals(string.Empty))
457 ValueNode(m_parser.ElementValue);
458 else
459 goto case JsonXmlReaderPosition.ValueContent;
460 460 m_position = JsonXmlReaderPosition.ValueContent;
461 461 return true;
462 462 } else {
@@ -521,7 +521,7 namespace Implab.Xml {
521 521 true
522 522 );
523 523 else
524 ElementNode(m_jsonValueName, m_jsonNamespace, elementAttrs, m_parser.ElementValue as string == string.Empty);
524 ElementNode(m_jsonValueName, m_jsonNamespace, elementAttrs, m_parser.ElementValue.Equals(string.Empty));
525 525 break;
526 526 default:
527 527 throw new Exception($"Unexpected JSON element {m_parser.ElementType}: {m_parser.ElementName}");
@@ -5,7 +5,7 using System.Text;
5 5 using System.Threading.Tasks;
6 6
7 7 namespace Implab.Xml {
8 public enum JsonXmlReaderPosition {
8 enum JsonXmlReaderPosition {
9 9 Initial,
10 10 Declaration,
11 11 BeginArray,
@@ -6,7 +6,7 using System.Threading.Tasks;
6 6 using System.Xml;
7 7
8 8 namespace Implab.Xml {
9 public class XmlNameContext {
9 class XmlNameContext {
10 10 public const string XmlnsNamespace = "http://www.w3.org/2000/xmlns/";
11 11 public const string XmlnsPrefix = "xmlns";
12 12 public const string XmlNamespace = "http://www.w3.org/XML/1998/namespace";
@@ -19,11 +19,17 namespace Implab.Xml {
19 19 Dictionary<string, string> m_ns2prefix;
20 20 Dictionary<string, string> m_prefix2ns;
21 21 int m_nextPrefix = 1;
22 string m_lastNs;
23 string m_lastPrefix;
22 24
23 25 public XmlNameContext ParentContext { get; private set; }
24 26
25 public XmlNameContext(XmlNameContext parent) {
27 public int Depth { get; private set; }
28
29 public XmlNameContext(XmlNameContext parent, int depth) {
26 30 ParentContext = parent;
31 Depth = depth;
32
27 33 if (parent == null) {
28 34 DefinePrefixNoCheck(XmlnsNamespace, XmlnsPrefix);
29 35 DefinePrefixNoCheck(XmlNamespace, XmlPrefix);
@@ -35,12 +41,17 namespace Implab.Xml {
35 41 public bool LookupNamespacePrefix(string ns, out string prefix) {
36 42 if (ns == null)
37 43 ns = string.Empty;
44 if (ns == m_lastNs) {
45 prefix = m_lastPrefix;
46 return true;
47 }
48
38 49
39 50 prefix = null;
40 51 for (var ctx = this; ctx != null; ctx = ctx.ParentContext) {
41 if (ctx.m_ns2prefix?.TryGetValue(ns, out prefix) == true) {
42 if (ctx != this) // cache for the future use
43 DefinePrefixNoCheck(ns, prefix);
52 if (ctx.m_ns2prefix != null && ctx.m_ns2prefix.TryGetValue(ns, out prefix)) {
53 m_lastNs = ns;
54 m_lastPrefix = prefix;
44 55 return true;
45 56 }
46 57 }
@@ -88,11 +99,8 namespace Implab.Xml {
88 99 prefix = string.Empty;
89 100 string ns = null;
90 101 for(var ctx = this; ctx != null; ctx = ctx.ParentContext) {
91 if (ctx.m_prefix2ns?.TryGetValue(prefix, out ns) == true) {
92 if (ctx != this) // cache for the future use
93 DefinePrefixNoCheck(ns, prefix);
102 if (ctx.m_prefix2ns != null && ctx.m_prefix2ns.TryGetValue(prefix, out ns) == true)
94 103 return ns;
95 }
96 104 }
97 105 return null;
98 106 }
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

ok, latest stable version should be in default

You need to be logged in to leave comments. Login now