├── README.md
├── TestApp
├── Properties
│ ├── Settings.settings
│ ├── Settings.Designer.cs
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ └── Resources.resx
├── Program.cs
├── Form1.cs
├── TestApp.csproj
├── Form1.resx
└── Form1.designer.cs
├── SqlParser
├── FromTag.cs
├── WhereTag.cs
├── SelectTag.cs
├── Properties
│ └── AssemblyInfo.cs
├── GroupByTag.cs
├── OrderByTag.cs
├── StartWith.cs
├── ForUpdateTag.cs
├── SqlParser.csproj
├── SimpleTwoWordTag.cs
├── QuotedIdentifierTag.cs
├── BracesTag.cs
├── StringLiteralTag.cs
├── SimpleOneWordTag.cs
├── SqlParser.cs
├── ClassDiagram.cd
├── TagBase.cs
└── ParserBase.cs
└── SqlParser.sln
/README.md:
--------------------------------------------------------------------------------
1 | [](https://waffle.io/totpero/SqlParser)
2 | # SqlParser
3 | SQL Query Parser projecr form CodeProject (http://www.codeproject.com/Articles/32524/SQL-Parser)
4 |
5 | Test
6 |
--------------------------------------------------------------------------------
/TestApp/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/TestApp/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Windows.Forms;
4 |
5 | namespace TestApp
6 | {
7 | static class Program
8 | {
9 | ///
10 | /// The main entry point for the application.
11 | ///
12 | [STAThread]
13 | static void Main()
14 | {
15 | Application.EnableVisualStyles();
16 | Application.SetCompatibleTextRenderingDefault(false);
17 | Application.Run(new Form1());
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/TestApp/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:2.0.50727.1434
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace TestApp.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/SqlParser/FromTag.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Parser
6 | {
7 | #region FromTag
8 |
9 | [TagType(FromTag.cTagName)]
10 | [MatchFromTag]
11 | internal class FromTag : SimpleOneWordTag
12 | {
13 | #region Consts
14 |
15 | ///
16 | /// The name of the tag (its identifier).
17 | ///
18 | public const string cTagName = "FROM";
19 |
20 | #endregion
21 |
22 | #region Properties
23 |
24 | ///
25 | /// Gets the name of the tag (its identifier and sql text)
26 | ///
27 | protected override string Name
28 | {
29 | get
30 | {
31 | return cTagName;
32 | }
33 | }
34 |
35 | #endregion
36 | }
37 |
38 | #endregion
39 |
40 | #region MatchFromTagAttribute
41 |
42 | internal class MatchFromTagAttribute : MatchSimpleOneWordTagAttribute
43 | {
44 | #region Properties
45 |
46 | ///
47 | /// Gets the name of the tag (its identifier and sql text)
48 | ///
49 | protected override string Name
50 | {
51 | get
52 | {
53 | return FromTag.cTagName;
54 | }
55 | }
56 |
57 | #endregion
58 | }
59 |
60 | #endregion
61 | }
62 |
--------------------------------------------------------------------------------
/SqlParser/WhereTag.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Parser
6 | {
7 | #region WhereTag
8 |
9 | [TagType(WhereTag.cTagName)]
10 | [MatchWhereTag]
11 | internal class WhereTag : SimpleOneWordTag
12 | {
13 | #region Consts
14 |
15 | ///
16 | /// The name of the tag (its identifier).
17 | ///
18 | public const string cTagName = "WHERE";
19 |
20 | #endregion
21 |
22 | #region Properties
23 |
24 | ///
25 | /// Gets the name of the tag (its identifier and sql text)
26 | ///
27 | protected override string Name
28 | {
29 | get
30 | {
31 | return cTagName;
32 | }
33 | }
34 |
35 | #endregion
36 | }
37 |
38 | #endregion
39 |
40 | #region MatchWhereTagAttribute
41 |
42 | internal class MatchWhereTagAttribute : MatchSimpleOneWordTagAttribute
43 | {
44 | #region Properties
45 |
46 | ///
47 | /// Gets the name of the tag (its identifier and sql text)
48 | ///
49 | protected override string Name
50 | {
51 | get
52 | {
53 | return WhereTag.cTagName;
54 | }
55 | }
56 |
57 | #endregion
58 | }
59 |
60 | #endregion
61 | }
62 |
--------------------------------------------------------------------------------
/SqlParser/SelectTag.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Parser
6 | {
7 | #region SelectTag
8 |
9 | [TagType(SelectTag.cTagName)]
10 | [MatchSelectTag]
11 | internal class SelectTag : SimpleOneWordTag
12 | {
13 | #region Consts
14 |
15 | ///
16 | /// The name of the tag (its identifier).
17 | ///
18 | public const string cTagName = "SELECT";
19 |
20 | #endregion
21 |
22 | #region Properties
23 |
24 | ///
25 | /// Gets the name of the tag (its identifier and sql text)
26 | ///
27 | protected override string Name
28 | {
29 | get
30 | {
31 | return cTagName;
32 | }
33 | }
34 |
35 | #endregion
36 | }
37 |
38 | #endregion
39 |
40 | #region MatchSelectTagAttribute
41 |
42 | internal class MatchSelectTagAttribute : MatchSimpleOneWordTagAttribute
43 | {
44 | #region Properties
45 |
46 | ///
47 | /// Gets the name of the tag (its identifier and sql text)
48 | ///
49 | protected override string Name
50 | {
51 | get
52 | {
53 | return SelectTag.cTagName;
54 | }
55 | }
56 |
57 | #endregion
58 | }
59 |
60 | #endregion
61 | }
62 |
--------------------------------------------------------------------------------
/SqlParser.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 9.00
3 | # Visual Studio 2005
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SqlParser", "SqlParser\SqlParser.csproj", "{8A0BB4FD-F01F-4B42-AACB-FC7CD368FEFB}"
5 | EndProject
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApp", "TestApp\TestApp.csproj", "{7E78BA0E-C411-4F2F-9B9C-110126347D80}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {8A0BB4FD-F01F-4B42-AACB-FC7CD368FEFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {8A0BB4FD-F01F-4B42-AACB-FC7CD368FEFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {8A0BB4FD-F01F-4B42-AACB-FC7CD368FEFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {8A0BB4FD-F01F-4B42-AACB-FC7CD368FEFB}.Release|Any CPU.Build.0 = Release|Any CPU
18 | {7E78BA0E-C411-4F2F-9B9C-110126347D80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {7E78BA0E-C411-4F2F-9B9C-110126347D80}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {7E78BA0E-C411-4F2F-9B9C-110126347D80}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {7E78BA0E-C411-4F2F-9B9C-110126347D80}.Release|Any CPU.Build.0 = Release|Any CPU
22 | EndGlobalSection
23 | GlobalSection(SolutionProperties) = preSolution
24 | HideSolutionNode = FALSE
25 | EndGlobalSection
26 | EndGlobal
27 |
--------------------------------------------------------------------------------
/TestApp/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
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("TestApp")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("TestApp")]
13 | [assembly: AssemblyCopyright("Copyright © 2009")]
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("ff85a389-3158-4ebe-9196-93ab0760fe58")]
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")]
37 |
--------------------------------------------------------------------------------
/SqlParser/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
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("SqlParser")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("SqlParser")]
13 | [assembly: AssemblyCopyright("Copyright © 2009")]
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("7c084735-40a7-4fc6-8906-9845c75a79d6")]
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")]
37 |
--------------------------------------------------------------------------------
/TestApp/Form1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Text;
7 | using System.Windows.Forms;
8 | using Parser;
9 |
10 | namespace TestApp
11 | {
12 | public partial class Form1 : Form
13 | {
14 | public Form1()
15 | {
16 | InitializeComponent();
17 | }
18 |
19 | private void fButtonModify_Click(object sender, EventArgs e)
20 | {
21 | if (string.IsNullOrEmpty(fTextBoxOriginal.Text.Trim()))
22 | {
23 | fTextBoxFinal.Text = string.Empty;
24 | return;
25 | }
26 |
27 | try
28 | {
29 | SqlParser myParser = new SqlParser();
30 | myParser.Parse(fTextBoxOriginal.Text);
31 |
32 | if (!string.IsNullOrEmpty(fTextBoxWhereClause.Text.Trim()))
33 | {
34 | string myOrginalWhereClause = myParser.WhereClause;
35 | if (string.IsNullOrEmpty(myOrginalWhereClause))
36 | myParser.WhereClause = fTextBoxWhereClause.Text;
37 | else
38 | myParser.WhereClause = string.Format("({0}) AND ({1})", myOrginalWhereClause, fTextBoxWhereClause.Text);
39 | }
40 |
41 | if (!string.IsNullOrEmpty(fTextBoxOrderBy.Text.Trim()))
42 | {
43 | string myOrginalOrderByClause = myParser.OrderByClause;
44 |
45 | if (string.IsNullOrEmpty(myOrginalOrderByClause))
46 | myParser.OrderByClause = fTextBoxOrderBy.Text;
47 | else
48 | myParser.OrderByClause = string.Format("{0}, {1}", myOrginalOrderByClause, fTextBoxOrderBy.Text);
49 | }
50 |
51 | fTextBoxFinal.Text = myParser.ToText();
52 | }
53 | catch (Exception myEx)
54 | {
55 | MessageBox.Show(myEx.Message);
56 | }
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/SqlParser/GroupByTag.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Parser
6 | {
7 | #region GroupByTag
8 |
9 | [TagType(GroupByTag.cTagName)]
10 | [MatchGroupByTag]
11 | internal class GroupByTag : SimpleTwoWordTag
12 | {
13 | #region Consts
14 |
15 | ///
16 | /// The name of the tag (its identifier).
17 | ///
18 | public const string cTagName = "GROUP_BY";
19 |
20 | ///
21 | /// The first part of tag.
22 | ///
23 | public const string cTagFirstPart = "GROUP";
24 |
25 | ///
26 | /// The second part of tag.
27 | ///
28 | public const string cTagSecondPart = "BY";
29 |
30 | #endregion
31 |
32 | #region Properties
33 |
34 | ///
35 | /// Gets the name of the tag.
36 | ///
37 | protected override string Name
38 | {
39 | get
40 | {
41 | return cTagName;
42 | }
43 | }
44 |
45 | ///
46 | /// Gets the first word of the tag.
47 | ///
48 | protected override string FirstWord
49 | {
50 | get
51 | {
52 | return cTagFirstPart;
53 | }
54 | }
55 |
56 | ///
57 | /// Gets the second word of the tag.
58 | ///
59 | protected override string SecondWord
60 | {
61 | get
62 | {
63 | return cTagSecondPart;
64 | }
65 | }
66 |
67 | #endregion
68 | }
69 |
70 | #endregion
71 |
72 | #region MatchGroupByTagAttribute
73 |
74 | internal class MatchGroupByTagAttribute : MatchSimpleTwoWordTagAttribute
75 | {
76 | #region Properties
77 |
78 | ///
79 | /// Gets the name of the tag (its identifier and sql text)
80 | ///
81 | protected override string Name
82 | {
83 | get
84 | {
85 | return GroupByTag.cTagName;
86 | }
87 | }
88 |
89 | ///
90 | /// Gets the first word of the tag.
91 | ///
92 | protected override string FirstWord
93 | {
94 | get
95 | {
96 | return GroupByTag.cTagFirstPart;
97 | }
98 | }
99 |
100 | ///
101 | /// Gets the second word of the tag.
102 | ///
103 | protected override string SecondWord
104 | {
105 | get
106 | {
107 | return GroupByTag.cTagSecondPart;
108 | }
109 | }
110 |
111 | #endregion
112 | }
113 |
114 | #endregion
115 | }
116 |
--------------------------------------------------------------------------------
/SqlParser/OrderByTag.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Parser
6 | {
7 | #region OrderByTag
8 |
9 | [TagType(OrderByTag.cTagName)]
10 | [MatchOrderByTag]
11 | internal class OrderByTag : SimpleTwoWordTag
12 | {
13 | #region Consts
14 |
15 | ///
16 | /// The name of the tag (its identifier).
17 | ///
18 | public const string cTagName = "ORDER_BY";
19 |
20 | ///
21 | /// The first part of tag.
22 | ///
23 | public const string cTagFirstPart = "ORDER";
24 |
25 | ///
26 | /// The second part of tag.
27 | ///
28 | public const string cTagSecondPart = "BY";
29 |
30 | #endregion
31 |
32 | #region Properties
33 |
34 | ///
35 | /// Gets the name of the tag.
36 | ///
37 | protected override string Name
38 | {
39 | get
40 | {
41 | return cTagName;
42 | }
43 | }
44 |
45 | ///
46 | /// Gets the first word of the tag.
47 | ///
48 | protected override string FirstWord
49 | {
50 | get
51 | {
52 | return cTagFirstPart;
53 | }
54 | }
55 |
56 | ///
57 | /// Gets the second word of the tag.
58 | ///
59 | protected override string SecondWord
60 | {
61 | get
62 | {
63 | return cTagSecondPart;
64 | }
65 | }
66 |
67 | #endregion
68 | }
69 |
70 | #endregion
71 |
72 | #region MatchOrderByTagAttribute
73 |
74 | internal class MatchOrderByTagAttribute : MatchSimpleTwoWordTagAttribute
75 | {
76 | #region Properties
77 |
78 | ///
79 | /// Gets the name of the tag (its identifier and sql text)
80 | ///
81 | protected override string Name
82 | {
83 | get
84 | {
85 | return OrderByTag.cTagName;
86 | }
87 | }
88 |
89 | ///
90 | /// Gets the first word of the tag.
91 | ///
92 | protected override string FirstWord
93 | {
94 | get
95 | {
96 | return OrderByTag.cTagFirstPart;
97 | }
98 | }
99 |
100 | ///
101 | /// Gets the second word of the tag.
102 | ///
103 | protected override string SecondWord
104 | {
105 | get
106 | {
107 | return OrderByTag.cTagSecondPart;
108 | }
109 | }
110 |
111 | #endregion
112 | }
113 |
114 | #endregion
115 | }
116 |
--------------------------------------------------------------------------------
/SqlParser/StartWith.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Parser
6 | {
7 | #region StartWith
8 |
9 | [TagType(StartWith.cTagName)]
10 | [MatchStartWithTag]
11 | internal class StartWith : SimpleTwoWordTag
12 | {
13 | #region Consts
14 |
15 | ///
16 | /// The name of the tag (its identifier).
17 | ///
18 | public const string cTagName = "START_WITH";
19 |
20 | ///
21 | /// The first part of tag.
22 | ///
23 | public const string cTagFirstPart = "START";
24 |
25 | ///
26 | /// The second part of tag.
27 | ///
28 | public const string cTagSecondPart = "WITH";
29 |
30 | #endregion
31 |
32 | #region Properties
33 |
34 | ///
35 | /// Gets the name of the tag.
36 | ///
37 | protected override string Name
38 | {
39 | get
40 | {
41 | return cTagName;
42 | }
43 | }
44 |
45 | ///
46 | /// Gets the first word of the tag.
47 | ///
48 | protected override string FirstWord
49 | {
50 | get
51 | {
52 | return cTagFirstPart;
53 | }
54 | }
55 |
56 | ///
57 | /// Gets the second word of the tag.
58 | ///
59 | protected override string SecondWord
60 | {
61 | get
62 | {
63 | return cTagSecondPart;
64 | }
65 | }
66 |
67 | #endregion
68 | }
69 |
70 | #endregion
71 |
72 | #region MatchOrderByTagAttribute
73 |
74 | internal class MatchStartWithTagAttribute : MatchSimpleTwoWordTagAttribute
75 | {
76 | #region Properties
77 |
78 | ///
79 | /// Gets the name of the tag (its identifier and sql text)
80 | ///
81 | protected override string Name
82 | {
83 | get
84 | {
85 | return StartWith.cTagName;
86 | }
87 | }
88 |
89 | ///
90 | /// Gets the first word of the tag.
91 | ///
92 | protected override string FirstWord
93 | {
94 | get
95 | {
96 | return StartWith.cTagFirstPart;
97 | }
98 | }
99 |
100 | ///
101 | /// Gets the second word of the tag.
102 | ///
103 | protected override string SecondWord
104 | {
105 | get
106 | {
107 | return StartWith.cTagSecondPart;
108 | }
109 | }
110 |
111 | #endregion
112 | }
113 |
114 | #endregion
115 | }
116 |
--------------------------------------------------------------------------------
/SqlParser/ForUpdateTag.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Parser
6 | {
7 | #region ForUpdateTag
8 |
9 | [TagType(ForUpdateTag.cTagName)]
10 | [MatchForUpdateTag]
11 | internal class ForUpdateTag : SimpleTwoWordTag
12 | {
13 | #region Consts
14 |
15 | ///
16 | /// The name of the tag (its identifier).
17 | ///
18 | public const string cTagName = "FOR_UPDATE";
19 |
20 | ///
21 | /// The first part of tag.
22 | ///
23 | public const string cTagFirstPart = "FOR";
24 |
25 | ///
26 | /// The second part of tag.
27 | ///
28 | public const string cTagSecondPart = "UPDATE";
29 |
30 | #endregion
31 |
32 | #region Properties
33 |
34 | ///
35 | /// Gets the name of the tag.
36 | ///
37 | protected override string Name
38 | {
39 | get
40 | {
41 | return cTagName;
42 | }
43 | }
44 |
45 | ///
46 | /// Gets the first word of the tag.
47 | ///
48 | protected override string FirstWord
49 | {
50 | get
51 | {
52 | return cTagFirstPart;
53 | }
54 | }
55 |
56 | ///
57 | /// Gets the second word of the tag.
58 | ///
59 | protected override string SecondWord
60 | {
61 | get
62 | {
63 | return cTagSecondPart;
64 | }
65 | }
66 |
67 | #endregion
68 | }
69 |
70 | #endregion
71 |
72 | #region MatchForUpdateTagAttribute
73 |
74 | internal class MatchForUpdateTagAttribute : MatchSimpleTwoWordTagAttribute
75 | {
76 | #region Properties
77 |
78 | ///
79 | /// Gets the name of the tag (its identifier and sql text)
80 | ///
81 | protected override string Name
82 | {
83 | get
84 | {
85 | return ForUpdateTag.cTagName;
86 | }
87 | }
88 |
89 | ///
90 | /// Gets the first word of the tag.
91 | ///
92 | protected override string FirstWord
93 | {
94 | get
95 | {
96 | return ForUpdateTag.cTagFirstPart;
97 | }
98 | }
99 |
100 | ///
101 | /// Gets the second word of the tag.
102 | ///
103 | protected override string SecondWord
104 | {
105 | get
106 | {
107 | return ForUpdateTag.cTagSecondPart;
108 | }
109 | }
110 |
111 | #endregion
112 | }
113 |
114 | #endregion
115 | }
116 |
--------------------------------------------------------------------------------
/SqlParser/SqlParser.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Debug
4 | AnyCPU
5 | 8.0.50727
6 | 2.0
7 | {8A0BB4FD-F01F-4B42-AACB-FC7CD368FEFB}
8 | Library
9 | Properties
10 | SqlParser
11 | SqlParser
12 |
13 |
14 | true
15 | full
16 | false
17 | bin\Debug\
18 | DEBUG;TRACE
19 | prompt
20 | 4
21 |
22 |
23 | pdbonly
24 | true
25 | bin\Release\
26 | TRACE
27 | prompt
28 | 4
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
64 |
--------------------------------------------------------------------------------
/TestApp/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:2.0.50727.1434
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace TestApp.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TestApp.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/SqlParser/SimpleTwoWordTag.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Parser
6 | {
7 | #region SimpleTwoWordTag
8 |
9 | ///
10 | /// The base class for such tags as Order By, Group By etc.
11 | ///
12 | internal abstract class SimpleTwoWordTag : SimpleOneWordTag
13 | {
14 | #region Methods
15 |
16 | #region Common
17 |
18 | ///
19 | /// Checks whether there is the tag at the specified position
20 | /// in the specified sql.
21 | ///
22 | ///
23 | /// The position after the tag or -1 there is no tag at the position.
24 | ///
25 | protected override int MatchStart(string sql, int position)
26 | {
27 | return MatchStart(FirstWord, SecondWord, sql, position);
28 | }
29 |
30 | ///
31 | /// Writes the start of the tag.
32 | ///
33 | public override void WriteStart(StringBuilder output)
34 | {
35 | CheckInitialized();
36 |
37 | #region Check the parameters
38 |
39 | if (output == null)
40 | throw new ArgumentNullException();
41 |
42 | #endregion
43 |
44 | output.Append(FirstWord);
45 | output.Append(ParserBase.cWhiteSpace);
46 | output.Append(SecondWord);
47 | }
48 |
49 | #endregion
50 |
51 | #region Static
52 |
53 | ///
54 | /// Checks whether there is the tag at the specified position
55 | /// in the specified sql.
56 | ///
57 | /// The value of the Name property.
58 | ///
59 | /// The position after the tag or -1 there is no tag at the position.
60 | ///
61 | internal static int MatchStart(string firstWord, string secondWord, string sql, int position)
62 | {
63 | #region Check the arguments
64 |
65 | ParserBase.CheckTextAndPositionArguments(sql, position);
66 |
67 | #endregion
68 |
69 | if (string.Compare(sql, position, firstWord, 0, firstWord.Length, true) != 0)
70 | return -1;
71 |
72 | position += firstWord.Length;
73 |
74 | ParserBase.SkipWhiteSpace(sql, ref position);
75 | if (position == sql.Length)
76 | return -1;
77 |
78 | if (string.Compare(sql, position, secondWord, 0, secondWord.Length, true) != 0)
79 | return -1;
80 |
81 | return position + secondWord.Length;
82 | }
83 |
84 | #endregion
85 |
86 | #endregion
87 |
88 | #region Properties
89 |
90 | ///
91 | /// Gets the first word of the tag.
92 | ///
93 | protected abstract string FirstWord { get; }
94 |
95 | ///
96 | /// Gets the second word of the tag.
97 | ///
98 | protected abstract string SecondWord { get; }
99 |
100 | #endregion
101 | }
102 |
103 | #endregion
104 |
105 | #region MatchSimpleTwoWordTagAttribute
106 |
107 | internal abstract class MatchSimpleTwoWordTagAttribute : MatchSimpleOneWordTagAttribute
108 | {
109 | #region Methods
110 |
111 | public override bool Match(string sql, int position)
112 | {
113 | return SimpleTwoWordTag.MatchStart(FirstWord, SecondWord, sql, position) >= 0;
114 | }
115 |
116 | #endregion
117 |
118 | #region Properties
119 |
120 | ///
121 | /// Gets the first word of the tag.
122 | ///
123 | protected abstract string FirstWord { get; }
124 |
125 | ///
126 | /// Gets the second word of the tag.
127 | ///
128 | protected abstract string SecondWord { get; }
129 |
130 | #endregion
131 | }
132 |
133 | #endregion
134 | }
135 |
--------------------------------------------------------------------------------
/SqlParser/QuotedIdentifierTag.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Parser
6 | {
7 | #region QuotedIdentifierTag
8 |
9 | [TagType(QuotedIdentifierTag.cTagName)]
10 | [MatchQuotedIdentifierTag]
11 | internal class QuotedIdentifierTag : TagBase
12 | {
13 | #region Consts
14 |
15 | ///
16 | /// The name of the tag (its identifier).
17 | ///
18 | public const string cTagName = "QUOTED_IDENTIFIER";
19 |
20 | ///
21 | /// The tag delimiter.
22 | ///
23 | public const string cTagDelimiter = "\"";
24 |
25 | #endregion
26 |
27 | #region Methods
28 |
29 | #region Common
30 |
31 | ///
32 | /// Reads the tag at the specified position in the specified word and separator array.
33 | ///
34 | ///
35 | /// The position after the tag (at which to continue reading).
36 | ///
37 | protected override int InitializeCoreFromText(ParserBase parser, string sql, int position, TagBase parentTag)
38 | {
39 | #region Check the arguments
40 |
41 | ParserBase.CheckTextAndPositionArguments(sql, position);
42 |
43 | #endregion
44 |
45 | int myAfterTagStartPos = MatchStartStatic(sql, position);
46 |
47 | if (myAfterTagStartPos < 0)
48 | throw new Exception("Cannot read the QuotedIdentifier tag.");
49 |
50 | #region Read the identifier's value
51 |
52 | int myTagEndPos = sql.IndexOf(cTagDelimiter, myAfterTagStartPos, StringComparison.InvariantCultureIgnoreCase);
53 | if (myTagEndPos < 0)
54 | throw new Exception("Cannot read the QuotedIdentifier tag.");
55 |
56 | if (myAfterTagStartPos == myTagEndPos)
57 | Value = string.Empty;
58 | else
59 | Value = sql.Substring(myAfterTagStartPos, myTagEndPos - myAfterTagStartPos);
60 |
61 | #endregion
62 |
63 | Parser = parser;
64 |
65 | HasContents = false;
66 |
67 | return myTagEndPos + cTagDelimiter.Length;
68 | }
69 |
70 | ///
71 | /// Writes the start of the tag.
72 | ///
73 | public override void WriteStart(StringBuilder output)
74 | {
75 | CheckInitialized();
76 |
77 | #region Check the parameters
78 |
79 | if (output == null)
80 | throw new ArgumentNullException();
81 |
82 | #endregion
83 |
84 | output.Append(cTagDelimiter);
85 | output.Append(Value);
86 | output.Append(cTagDelimiter);
87 | }
88 |
89 | #endregion
90 |
91 | #region Static
92 |
93 | ///
94 | /// Checks whether there is the tag start at the specified position
95 | /// in the specified sql.
96 | ///
97 | ///
98 | /// The position after the tag or -1 there is no tag start at the position.
99 | ///
100 | public static int MatchStartStatic(string sql, int position)
101 | {
102 | #region Check the arguments
103 |
104 | ParserBase.CheckTextAndPositionArguments(sql, position);
105 |
106 | #endregion
107 |
108 | if (string.Compare(sql, position, cTagDelimiter, 0, cTagDelimiter.Length, true) != 0)
109 | return -1;
110 |
111 | return position + cTagDelimiter.Length;
112 | }
113 |
114 | #endregion
115 |
116 | #endregion
117 | }
118 |
119 | #endregion
120 |
121 | #region MatchQuotedIdentifierTagAttribute
122 |
123 | internal class MatchQuotedIdentifierTagAttribute : MatchTagAttributeBase
124 | {
125 | #region Methods
126 |
127 | public override bool Match(string sql, int position)
128 | {
129 | return QuotedIdentifierTag.MatchStartStatic(sql, position) >= 0;
130 | }
131 |
132 | #endregion
133 | }
134 |
135 | #endregion
136 | }
137 |
--------------------------------------------------------------------------------
/TestApp/TestApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Debug
4 | AnyCPU
5 | 8.0.50727
6 | 2.0
7 | {7E78BA0E-C411-4F2F-9B9C-110126347D80}
8 | WinExe
9 | Properties
10 | TestApp
11 | TestApp
12 |
13 |
14 | true
15 | full
16 | false
17 | bin\Debug\
18 | DEBUG;TRACE
19 | prompt
20 | 4
21 |
22 |
23 | pdbonly
24 | true
25 | bin\Release\
26 | TRACE
27 | prompt
28 | 4
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | Form1.cs
41 | Designer
42 |
43 |
44 | ResXFileCodeGenerator
45 | Resources.Designer.cs
46 | Designer
47 |
48 |
49 |
50 | Form
51 |
52 |
53 | Form1.cs
54 |
55 |
56 |
57 | True
58 | Resources.resx
59 | True
60 |
61 |
62 | SettingsSingleFileGenerator
63 | Settings.Designer.cs
64 |
65 |
66 | True
67 | Settings.settings
68 | True
69 |
70 |
71 |
72 |
73 | {8A0BB4FD-F01F-4B42-AACB-FC7CD368FEFB}
74 | SqlParser
75 |
76 |
77 |
78 |
85 |
--------------------------------------------------------------------------------
/SqlParser/BracesTag.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Parser
6 | {
7 | #region BracesTag
8 |
9 | [TagType(BracesTag.cTagName)]
10 | [MatchBracesTag]
11 | internal class BracesTag : TagBase
12 | {
13 | #region Consts
14 |
15 | ///
16 | /// The name of the tag (its identifier).
17 | ///
18 | public const string cTagName = "BRACES";
19 |
20 | ///
21 | /// The start of the tag.
22 | ///
23 | public const string cStartTag = "(";
24 |
25 | ///
26 | /// The end of the tag.
27 | ///
28 | public const string cEndTag = ")";
29 |
30 | #endregion
31 |
32 | #region Methods
33 |
34 | #region Common
35 |
36 | ///
37 | /// Reads the tag at the specified position in the specified word and separator array.
38 | ///
39 | ///
40 | /// The position after the tag (at which to continue reading).
41 | ///
42 | protected override int InitializeCoreFromText(ParserBase parser, string sql, int position, TagBase parentTag)
43 | {
44 | #region Check the arguments
45 |
46 | ParserBase.CheckTextAndPositionArguments(sql, position);
47 |
48 | #endregion
49 |
50 | int myResult = MatchStartStatic(sql, position);
51 |
52 | if (myResult < 0)
53 | throw new Exception("Cannot read the Braces tag.");
54 |
55 | Parser = parser;
56 |
57 | HasContents = true;
58 |
59 | return myResult;
60 | }
61 |
62 | ///
63 | /// Returns a value indicating whether there is the tag ending at the specified position. ///
64 | ///
65 | ///
66 | /// If this value is less than zero, then there is no ending; otherwise the
67 | /// position after ending is returned.
68 | ///
69 | public override int MatchEnd(string sql, int position)
70 | {
71 | CheckInitialized();
72 |
73 | #region Check the arguments
74 |
75 | ParserBase.CheckTextAndPositionArguments(sql, position);
76 |
77 | #endregion
78 |
79 | return MatchEndStatic(sql, position);
80 | }
81 |
82 | ///
83 | /// Writes the start of the tag.
84 | ///
85 | public override void WriteStart(StringBuilder output)
86 | {
87 | CheckInitialized();
88 |
89 | #region Check the parameters
90 |
91 | if (output == null)
92 | throw new ArgumentNullException();
93 |
94 | #endregion
95 |
96 | output.Append(cStartTag);
97 | }
98 |
99 | ///
100 | /// Writes the end of the tag.
101 | ///
102 | public override void WriteEnd(StringBuilder output)
103 | {
104 | CheckInitialized();
105 |
106 | #region Check the parameters
107 |
108 | if (output == null)
109 | throw new ArgumentNullException();
110 |
111 | #endregion
112 |
113 | output.Append(cEndTag);
114 | }
115 |
116 | #endregion
117 |
118 | #region Static
119 |
120 | ///
121 | /// Checks whether there is the tag start at the specified position
122 | /// in the specified sql.
123 | ///
124 | ///
125 | /// The position after the tag or -1 there is no tag start at the position.
126 | ///
127 | public static int MatchStartStatic(string sql, int position)
128 | {
129 | #region Check the arguments
130 |
131 | ParserBase.CheckTextAndPositionArguments(sql, position);
132 |
133 | #endregion
134 |
135 | if (string.Compare(sql, position, cStartTag, 0, cStartTag.Length, true) != 0)
136 | return -1;
137 |
138 | return position + cStartTag.Length;
139 | }
140 |
141 | ///
142 | /// Checks whether there is the tag end at the specified position
143 | /// in the specified sql.
144 | ///
145 | ///
146 | /// The position after the tag or -1 there is no tag end at the position.
147 | ///
148 | public static int MatchEndStatic(string sql, int position)
149 | {
150 | #region Check the arguments
151 |
152 | ParserBase.CheckTextAndPositionArguments(sql, position);
153 |
154 | #endregion
155 |
156 | if (string.Compare(sql, position, cEndTag, 0, cEndTag.Length, true) != 0)
157 | return -1;
158 |
159 | return position + cEndTag.Length;
160 | }
161 |
162 | #endregion
163 |
164 | #endregion
165 | }
166 |
167 | #endregion
168 |
169 | #region MatchBracesTagAttribute
170 |
171 | internal class MatchBracesTagAttribute : MatchTagAttributeBase
172 | {
173 | #region Methods
174 |
175 | public override bool Match(string sql, int position)
176 | {
177 | return BracesTag.MatchStartStatic(sql, position) >= 0;
178 | }
179 |
180 | #endregion
181 | }
182 |
183 | #endregion
184 | }
185 |
--------------------------------------------------------------------------------
/TestApp/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/SqlParser/StringLiteralTag.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Parser
6 | {
7 | #region StringLiteralTag
8 |
9 | [TagType(StringLiteralTag.cTagName)]
10 | [MatchStringLiteralTag]
11 | internal class StringLiteralTag : TagBase
12 | {
13 | #region Consts
14 |
15 | ///
16 | /// The name of the tag (its identifier).
17 | ///
18 | public const string cTagName = "STRING_LITERAL";
19 |
20 | ///
21 | /// The tag.
22 | ///
23 | public const string cTagDelimiter = "'";
24 |
25 | #endregion
26 |
27 | #region Methods
28 |
29 | #region Common
30 |
31 | ///
32 | /// Reads the tag at the specified position in the specified sql string.
33 | ///
34 | ///
35 | /// The position after the tag (at which to continue reading).
36 | ///
37 | protected override int InitializeCoreFromText(ParserBase parser, string sql, int position, TagBase parentTag)
38 | {
39 | #region Check the arguments
40 |
41 | ParserBase.CheckTextAndPositionArguments(sql, position);
42 |
43 | #endregion
44 |
45 | int myLiteralStartPos = position;
46 |
47 | position = MatchStartStatic(sql, position);
48 |
49 | if (position < 0)
50 | throw new Exception("Cannot read the StringLiteral tag.");
51 |
52 | #region Read the literal value
53 |
54 | int myResult = -1;
55 | int myValueStartPos = position;
56 | while (position < sql.Length)
57 | {
58 | myResult = MatchEnd(sql, position, myLiteralStartPos);
59 | if (myResult >= 0)
60 | {
61 | if (position == myValueStartPos)
62 | Value = string.Empty;
63 | else
64 | Value = sql.Substring(myValueStartPos, position - myValueStartPos);
65 | break;
66 | }
67 | position++;
68 | }
69 |
70 | if (myResult < 0)
71 | throw new Exception("Cannot read the StringLiteral tag.");
72 |
73 | #endregion
74 |
75 | Parser = parser;
76 |
77 | HasContents = false;
78 |
79 | return myResult;
80 | }
81 |
82 | ///
83 | /// Returns a value indicating whether there is the tag ending at the specified position.
84 | ///
85 | ///
86 | /// If this value is less than zero, then there is no ending; otherwise the
87 | /// position after ending is returned.
88 | ///
89 | private int MatchEnd(string sql, int position, int literalStartPos)
90 | {
91 | #region Check the arguments
92 |
93 | ParserBase.CheckTextAndPositionArguments(sql, position);
94 |
95 | #endregion
96 |
97 | if (string.Compare(sql, position, cTagDelimiter, 0, cTagDelimiter.Length, true) != 0)
98 | return -1;
99 |
100 | #region Check the next and previous symbols (where there are ' symbols)
101 |
102 | #region Determine the number of ' symbols before
103 |
104 | int myNumberOfApostBefore = 0;
105 | for (int myCurPos = position - 1; myCurPos >= literalStartPos; myCurPos--)
106 | {
107 | if (string.Compare(sql, myCurPos, cTagDelimiter, 0, cTagDelimiter.Length, true) == 0)
108 | myNumberOfApostBefore++;
109 | else
110 | break;
111 | }
112 |
113 | #endregion
114 |
115 | if (!(myNumberOfApostBefore == 1 && position == literalStartPos + 1))
116 | {
117 | if (myNumberOfApostBefore % 2 == 1)
118 | return -1;
119 |
120 | #region Check whether the next symbol is '
121 |
122 | if (position + 1 < sql.Length)
123 | {
124 | if (string.Compare(sql, position + 1, cTagDelimiter, 0, cTagDelimiter.Length, true) == 0)
125 | return -1;
126 | }
127 |
128 | #endregion
129 | }
130 |
131 | #endregion
132 |
133 | return position + cTagDelimiter.Length;
134 | }
135 |
136 | ///
137 | /// Writes the start of the tag.
138 | ///
139 | public override void WriteStart(StringBuilder output)
140 | {
141 | CheckInitialized();
142 |
143 | #region Check the parameters
144 |
145 | if (output == null)
146 | throw new ArgumentNullException();
147 |
148 | #endregion
149 |
150 | output.Append(cTagDelimiter);
151 | output.Append(Value);
152 | WriteEnd(output);
153 | }
154 |
155 | ///
156 | /// Writes the end of the tag.
157 | ///
158 | private new void WriteEnd(StringBuilder output)
159 | {
160 | CheckInitialized();
161 |
162 | #region Check the parameters
163 |
164 | if (output == null)
165 | throw new ArgumentNullException();
166 |
167 | #endregion
168 |
169 | output.Append(cTagDelimiter);
170 | }
171 |
172 | #endregion
173 |
174 | #region Static
175 |
176 | ///
177 | /// Checks whether there is the tag start at the specified position
178 | /// in the specified sql.
179 | ///
180 | ///
181 | /// The position after the tag or -1 there is no tag start at the position.
182 | ///
183 | public static int MatchStartStatic(string sql, int position)
184 | {
185 | #region Check the arguments
186 |
187 | ParserBase.CheckTextAndPositionArguments(sql, position);
188 |
189 | #endregion
190 |
191 | if (string.Compare(sql, position, cTagDelimiter, 0, cTagDelimiter.Length, true) != 0)
192 | return -1;
193 |
194 | return position + cTagDelimiter.Length;
195 | }
196 |
197 | #endregion
198 |
199 | #endregion
200 | }
201 |
202 | #endregion
203 |
204 | #region MatchStringLiteralTagAttribute
205 |
206 | internal class MatchStringLiteralTagAttribute : MatchTagAttributeBase
207 | {
208 | #region Methods
209 |
210 | public override bool Match(string sql, int position)
211 | {
212 | return StringLiteralTag.MatchStartStatic(sql, position) >= 0;
213 | }
214 |
215 | #endregion
216 | }
217 |
218 | #endregion
219 | }
220 |
--------------------------------------------------------------------------------
/SqlParser/SimpleOneWordTag.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Parser
6 | {
7 | #region SimpleOneWordTag
8 |
9 | ///
10 | /// The base class for such tags as Select, From etc.
11 | ///
12 | internal abstract class SimpleOneWordTag: TagBase
13 | {
14 | #region Fields
15 |
16 | ///
17 | /// The value of the ParentTag property.
18 | ///
19 | private TagBase fParentTag;
20 |
21 | #endregion
22 |
23 | #region Methods
24 |
25 | #region Common
26 |
27 | ///
28 | /// Reads the tag at the specified position in the specified sql.
29 | ///
30 | ///
31 | /// The position after the tag (at which to continue reading).
32 | ///
33 | protected override int InitializeCoreFromText(ParserBase parser, string sql, int position, TagBase parentTag)
34 | {
35 | #region Check the arguments
36 |
37 | ParserBase.CheckTextAndPositionArguments(sql, position);
38 |
39 | #endregion
40 |
41 | int myResult = MatchStart(sql, position);
42 |
43 | if (myResult < 0)
44 | throw new Exception(string.Format("Cannot read the {0} tag.", Name));
45 |
46 | Parser = parser;
47 |
48 | HasContents = true;
49 |
50 | ParentTag = parentTag;
51 |
52 | return myResult;
53 | }
54 |
55 | ///
56 | /// Checks whether there is the tag at the specified position
57 | /// in the specified sql.
58 | ///
59 | ///
60 | /// The position after the tag or -1 there is no tag at the position.
61 | ///
62 | protected virtual int MatchStart(string sql, int position)
63 | {
64 | return MatchStart(Name, sql, position);
65 | }
66 |
67 | ///
68 | /// Writes the start of the tag.
69 | ///
70 | public override void WriteStart(StringBuilder output)
71 | {
72 | CheckInitialized();
73 |
74 | #region Check the parameters
75 |
76 | if (output == null)
77 | throw new ArgumentNullException();
78 |
79 | #endregion
80 |
81 | output.Append(Name);
82 | }
83 |
84 | ///
85 | /// Writes the end of the tag.
86 | ///
87 | public override void WriteEnd(StringBuilder output)
88 | {
89 | CheckInitialized();
90 |
91 | #region Check the parameters
92 |
93 | if (output == null)
94 | throw new ArgumentNullException();
95 |
96 | #endregion
97 |
98 | return;
99 | }
100 |
101 | ///
102 | /// Returns a value indicating whether there is the tag ending at the specified position.
103 | ///
104 | ///
105 | /// If this value is less than zero, then there is no ending; otherwise the
106 | /// position after ending is returned.
107 | ///
108 | public override int MatchEnd(string sql, int position)
109 | {
110 | CheckInitialized();
111 |
112 | #region Check the arguments
113 |
114 | ParserBase.CheckTextAndPositionArguments(sql, position);
115 |
116 | #endregion
117 |
118 | if (ParentTag != null && ParentTag.MatchEnd(sql, position) >= 0)
119 | return position;
120 |
121 | Type myTag = (Parser as SqlParser).IsTag(sql, position);
122 | if (
123 | myTag != null &&
124 | !myTag.IsAssignableFrom(typeof(StringLiteralTag)) &&
125 | !myTag.IsAssignableFrom(typeof(BracesTag))
126 | )
127 | return position;
128 |
129 | return -1;
130 | }
131 |
132 | #endregion
133 |
134 | #region Static
135 |
136 | ///
137 | /// Checks whether there is the tag at the specified position
138 | /// in the specified sql.
139 | ///
140 | /// The value of the Name property.
141 | ///
142 | /// The position after the tag or -1 there is no tag at the position.
143 | ///
144 | internal static int MatchStart(string name, string sql, int position)
145 | {
146 | #region Check the arguments
147 |
148 | if (name == null)
149 | throw new ArgumentNullException("name");
150 |
151 | ParserBase.CheckTextAndPositionArguments(sql, position);
152 |
153 | #endregion
154 |
155 | if (string.Compare(sql, position, name, 0, name.Length, true) != 0)
156 | return -1;
157 |
158 | return position + name.Length;
159 | }
160 |
161 | #endregion
162 |
163 | #endregion
164 |
165 | #region Properties
166 |
167 | ///
168 | /// Gets the name of the tag (its identifier and sql text)
169 | ///
170 | protected abstract string Name { get; }
171 |
172 | ///
173 | /// Inidicates whether the string end can be treated as the end of the tag.
174 | ///
175 | public override bool CanTerminateByStringEnd
176 | {
177 | get
178 | {
179 | CheckInitialized();
180 |
181 | return true;
182 | }
183 | }
184 |
185 | ///
186 | /// Returns the parent tag of this tag in the sql being parsed.
187 | ///
188 | public TagBase ParentTag
189 | {
190 | get
191 | {
192 | return fParentTag;
193 | }
194 | private set
195 | {
196 | fParentTag = value;
197 | }
198 | }
199 |
200 | #endregion
201 | }
202 |
203 | #endregion
204 |
205 | #region MatchSimpleOneWordTagAttribute
206 |
207 | internal abstract class MatchSimpleOneWordTagAttribute: MatchTagAttributeBase
208 | {
209 | #region Methods
210 |
211 | public override bool Match(string sql, int position)
212 | {
213 | return SimpleOneWordTag.MatchStart(Name, sql, position) >= 0;
214 | }
215 |
216 | #endregion
217 |
218 | #region Properties
219 |
220 | ///
221 | /// Gets the name of the tag (its identifier and sql text)
222 | ///
223 | protected abstract string Name { get; }
224 |
225 | #endregion
226 | }
227 |
228 | #endregion
229 | }
230 |
--------------------------------------------------------------------------------
/TestApp/Form1.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | SELECT LPAD(' ',2*(LEVEL-1)) || LAST_NAME ORG_CHART,
122 | EMPLOYEE_ID, MANAGER_ID, JOB_ID
123 | FROM EMPLOYEES
124 | WHERE JOB_ID != 'FI_MGR'
125 | START WITH JOB_ID = 'AD_VP'
126 | CONNECT BY PRIOR EMPLOYEE_ID = MANAGER_ID;
127 |
128 |
129 |
--------------------------------------------------------------------------------
/TestApp/Form1.designer.cs:
--------------------------------------------------------------------------------
1 | namespace TestApp
2 | {
3 | partial class Form1
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
32 | this.fTextBoxOriginal = new System.Windows.Forms.TextBox();
33 | this.label1 = new System.Windows.Forms.Label();
34 | this.label2 = new System.Windows.Forms.Label();
35 | this.fTextBoxWhereClause = new System.Windows.Forms.TextBox();
36 | this.fTextBoxOrderBy = new System.Windows.Forms.TextBox();
37 | this.label3 = new System.Windows.Forms.Label();
38 | this.label4 = new System.Windows.Forms.Label();
39 | this.fTextBoxFinal = new System.Windows.Forms.TextBox();
40 | this.fButtonModify = new System.Windows.Forms.Button();
41 | this.SuspendLayout();
42 | //
43 | // fTextBoxOriginal
44 | //
45 | this.fTextBoxOriginal.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
46 | | System.Windows.Forms.AnchorStyles.Right)));
47 | this.fTextBoxOriginal.Location = new System.Drawing.Point(15, 25);
48 | this.fTextBoxOriginal.Multiline = true;
49 | this.fTextBoxOriginal.Name = "fTextBoxOriginal";
50 | this.fTextBoxOriginal.Size = new System.Drawing.Size(617, 126);
51 | this.fTextBoxOriginal.TabIndex = 1;
52 | this.fTextBoxOriginal.Text = resources.GetString("fTextBoxOriginal.Text");
53 | //
54 | // label1
55 | //
56 | this.label1.AutoSize = true;
57 | this.label1.Location = new System.Drawing.Point(12, 9);
58 | this.label1.Name = "label1";
59 | this.label1.Size = new System.Drawing.Size(69, 13);
60 | this.label1.TabIndex = 0;
61 | this.label1.Text = "Original SQL:";
62 | //
63 | // label2
64 | //
65 | this.label2.AutoSize = true;
66 | this.label2.Location = new System.Drawing.Point(12, 157);
67 | this.label2.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0);
68 | this.label2.Name = "label2";
69 | this.label2.Size = new System.Drawing.Size(126, 13);
70 | this.label2.TabIndex = 2;
71 | this.label2.Text = "Additional Where clause:";
72 | //
73 | // fTextBoxWhereClause
74 | //
75 | this.fTextBoxWhereClause.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
76 | | System.Windows.Forms.AnchorStyles.Right)));
77 | this.fTextBoxWhereClause.Location = new System.Drawing.Point(12, 173);
78 | this.fTextBoxWhereClause.Multiline = true;
79 | this.fTextBoxWhereClause.Name = "fTextBoxWhereClause";
80 | this.fTextBoxWhereClause.Size = new System.Drawing.Size(620, 61);
81 | this.fTextBoxWhereClause.TabIndex = 3;
82 | this.fTextBoxWhereClause.Text = "SALARY > 2500";
83 | //
84 | // fTextBoxOrderBy
85 | //
86 | this.fTextBoxOrderBy.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
87 | | System.Windows.Forms.AnchorStyles.Right)));
88 | this.fTextBoxOrderBy.Location = new System.Drawing.Point(12, 256);
89 | this.fTextBoxOrderBy.Multiline = true;
90 | this.fTextBoxOrderBy.Name = "fTextBoxOrderBy";
91 | this.fTextBoxOrderBy.Size = new System.Drawing.Size(620, 61);
92 | this.fTextBoxOrderBy.TabIndex = 5;
93 | this.fTextBoxOrderBy.Text = "SALARY";
94 | //
95 | // label3
96 | //
97 | this.label3.AutoSize = true;
98 | this.label3.Location = new System.Drawing.Point(12, 240);
99 | this.label3.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0);
100 | this.label3.Name = "label3";
101 | this.label3.Size = new System.Drawing.Size(137, 13);
102 | this.label3.TabIndex = 4;
103 | this.label3.Text = "Additional Order By clause:";
104 | //
105 | // label4
106 | //
107 | this.label4.AutoSize = true;
108 | this.label4.Location = new System.Drawing.Point(12, 352);
109 | this.label4.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0);
110 | this.label4.Name = "label4";
111 | this.label4.Size = new System.Drawing.Size(55, 13);
112 | this.label4.TabIndex = 7;
113 | this.label4.Text = "Final SQL:";
114 | //
115 | // fTextBoxFinal
116 | //
117 | this.fTextBoxFinal.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
118 | | System.Windows.Forms.AnchorStyles.Left)
119 | | System.Windows.Forms.AnchorStyles.Right)));
120 | this.fTextBoxFinal.Location = new System.Drawing.Point(15, 368);
121 | this.fTextBoxFinal.Multiline = true;
122 | this.fTextBoxFinal.Name = "fTextBoxFinal";
123 | this.fTextBoxFinal.Size = new System.Drawing.Size(620, 131);
124 | this.fTextBoxFinal.TabIndex = 8;
125 | //
126 | // fButtonModify
127 | //
128 | this.fButtonModify.Location = new System.Drawing.Point(12, 323);
129 | this.fButtonModify.Name = "fButtonModify";
130 | this.fButtonModify.Size = new System.Drawing.Size(75, 23);
131 | this.fButtonModify.TabIndex = 6;
132 | this.fButtonModify.Text = "Modify SQL";
133 | this.fButtonModify.UseVisualStyleBackColor = true;
134 | this.fButtonModify.Click += new System.EventHandler(this.fButtonModify_Click);
135 | //
136 | // Form1
137 | //
138 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
139 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
140 | this.ClientSize = new System.Drawing.Size(644, 511);
141 | this.Controls.Add(this.fButtonModify);
142 | this.Controls.Add(this.label4);
143 | this.Controls.Add(this.fTextBoxFinal);
144 | this.Controls.Add(this.fTextBoxOrderBy);
145 | this.Controls.Add(this.label3);
146 | this.Controls.Add(this.fTextBoxWhereClause);
147 | this.Controls.Add(this.label2);
148 | this.Controls.Add(this.label1);
149 | this.Controls.Add(this.fTextBoxOriginal);
150 | this.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
151 | this.Name = "Form1";
152 | this.Text = "Form1";
153 | this.ResumeLayout(false);
154 | this.PerformLayout();
155 |
156 | }
157 |
158 | #endregion
159 |
160 | private System.Windows.Forms.TextBox fTextBoxOriginal;
161 | private System.Windows.Forms.Label label1;
162 | private System.Windows.Forms.Label label2;
163 | private System.Windows.Forms.TextBox fTextBoxWhereClause;
164 | private System.Windows.Forms.TextBox fTextBoxOrderBy;
165 | private System.Windows.Forms.Label label3;
166 | private System.Windows.Forms.Label label4;
167 | private System.Windows.Forms.TextBox fTextBoxFinal;
168 | private System.Windows.Forms.Button fButtonModify;
169 | }
170 | }
171 |
172 |
--------------------------------------------------------------------------------
/SqlParser/SqlParser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Xml;
4 |
5 | namespace Parser
6 | {
7 | #region SqlParser
8 |
9 | public class SqlParser: ParserBase
10 | {
11 | #region Base class implementation
12 |
13 | #region Fields
14 |
15 | ///
16 | /// Stores the types of all the possible tags.
17 | ///
18 | Type[] fTags;
19 |
20 | #endregion
21 |
22 | #region Properties
23 |
24 | ///
25 | /// Indicates whether the white space is a non-valueable character.
26 | ///
27 | protected override bool IsSkipWhiteSpace
28 | {
29 | get
30 | {
31 | return true;
32 | }
33 | }
34 |
35 | ///
36 | /// Returns the list of all the available tags.
37 | ///
38 | protected override Type[] Tags
39 | {
40 | get
41 | {
42 | if (fTags == null)
43 | {
44 | fTags = new Type[] {
45 | typeof(SelectTag),
46 | typeof(FromTag),
47 | typeof(WhereTag),
48 | typeof(OrderByTag),
49 | typeof(BracesTag),
50 | typeof(StringLiteralTag),
51 | typeof(ForUpdateTag),
52 | typeof(StartWith),
53 | typeof(GroupByTag),
54 | typeof(QuotedIdentifierTag)
55 | };
56 | }
57 |
58 | return fTags;
59 | }
60 | }
61 |
62 | #endregion
63 |
64 | #endregion
65 |
66 | #region Common
67 |
68 | #region Methods
69 |
70 | ///
71 | /// Returns the xml node which corresponds to the From tag.
72 | /// If this node does not exist, this method generates an
73 | /// exception.
74 | ///
75 | private XmlNode GetFromTagXmlNode()
76 | {
77 | XmlNode myFromNode = ParsedDocument.SelectSingleNode(string.Format(@"{0}/{1}[@{2}='{3}']", cRootXmlNodeName, cTagXmlNodeName, cTagTypeXmlAttributeName, FromTag.cTagName));
78 | if (myFromNode == null)
79 | throw new Exception(ToText());
80 |
81 | return myFromNode;
82 | }
83 |
84 | ///
85 | /// Returns the xml node which corresponds to the For Update tag.
86 | ///
87 | private XmlNode GetForUpdateTagXmlNode()
88 | {
89 | XmlNode myForUpdateNode = ParsedDocument.SelectSingleNode(string.Format(@"{0}/{1}[@{2}='{3}']", cRootXmlNodeName, cTagXmlNodeName, cTagTypeXmlAttributeName, ForUpdateTag.cTagName));
90 |
91 | return myForUpdateNode;
92 | }
93 |
94 | ///
95 | /// Checks whether there is a tag in the text at the specified position, and returns its tag.
96 | ///
97 | internal new Type IsTag(string text, int position)
98 | {
99 | return base.IsTag(text, position);
100 | }
101 |
102 | #endregion
103 |
104 | #endregion
105 |
106 | #region Where Clause
107 |
108 | #region Methods
109 |
110 | ///
111 | /// Returns the xml node which corresponds to the Where tag.
112 | /// If this node does not exist, creates a new one (if needed).
113 | ///
114 | private XmlNode GetWhereTagXmlNode(bool createNew)
115 | {
116 | XmlNode myWhereNode = ParsedDocument.SelectSingleNode(string.Format(@"{0}/{1}[@{2}='{3}']", cRootXmlNodeName, cTagXmlNodeName, cTagTypeXmlAttributeName, WhereTag.cTagName));
117 | if (myWhereNode == null && createNew)
118 | {
119 | WhereTag myWhereTag = new WhereTag();
120 | myWhereTag.InitializeFromData(this, null, false);
121 | myWhereNode = CreateTagXmlNode(myWhereTag);
122 |
123 | XmlNode myFromNode = GetFromTagXmlNode();
124 | myFromNode.ParentNode.InsertAfter(myWhereNode, myFromNode);
125 | }
126 |
127 | return myWhereNode;
128 | }
129 |
130 | #endregion
131 |
132 | #region Properties
133 |
134 | ///
135 | /// Gets or sets the Where clause of the parsed sql.
136 | ///
137 | public string WhereClause
138 | {
139 | get
140 | {
141 | #region Get the Where xml node
142 |
143 | XmlNode myWhereTagXmlNode = GetWhereTagXmlNode(false);
144 | if (myWhereTagXmlNode == null)
145 | return string.Empty;
146 |
147 | #endregion
148 |
149 | StringBuilder myStringBuilder = new StringBuilder();
150 | XmlNodesToText(myStringBuilder, myWhereTagXmlNode.ChildNodes);
151 | return myStringBuilder.ToString();
152 | }
153 | set
154 | {
155 | if (string.IsNullOrEmpty(value))
156 | {
157 | #region Remove the Where xml node
158 |
159 | XmlNode myWhereXmlNode = GetWhereTagXmlNode(false);
160 | if (myWhereXmlNode != null)
161 | myWhereXmlNode.ParentNode.RemoveChild(myWhereXmlNode);
162 |
163 | #endregion
164 | }
165 | else
166 | {
167 | #region Modify the Where xml node
168 |
169 | XmlNode myWhereXmlNode = GetWhereTagXmlNode(true);
170 |
171 | ClearXmlNode(myWhereXmlNode);
172 |
173 | TagBase myWhereTag = TagXmlNodeToTag(myWhereXmlNode);
174 |
175 | ParseBlock(myWhereXmlNode, myWhereTag, value, 0);
176 |
177 | #endregion
178 | }
179 | }
180 | }
181 |
182 | #endregion
183 |
184 | #endregion
185 |
186 | #region Order By Clause
187 |
188 | #region Methods
189 |
190 | ///
191 | /// Returns the xml node which corresponds to the Order By tag.
192 | /// If this node does not exist, creates a new one (if needed).
193 | ///
194 | private XmlNode GetOrderByTagXmlNode(bool createNew)
195 | {
196 | XmlNode myOrderByNode = ParsedDocument.SelectSingleNode(string.Format(@"{0}/{1}[@{2}='{3}']", cRootXmlNodeName, cTagXmlNodeName, cTagTypeXmlAttributeName, OrderByTag.cTagName));
197 | if (myOrderByNode == null && createNew)
198 | {
199 | OrderByTag myOrderByTag = new OrderByTag();
200 | myOrderByTag.InitializeFromData(this, null, false);
201 | myOrderByNode = CreateTagXmlNode(myOrderByTag);
202 |
203 | XmlNode myForUpdateNode = GetForUpdateTagXmlNode();
204 | if (myForUpdateNode != null)
205 | {
206 | myForUpdateNode.ParentNode.InsertBefore(myOrderByNode, myForUpdateNode);
207 | return myOrderByNode;
208 | }
209 |
210 | XmlNode myFromNode = GetFromTagXmlNode();
211 | myFromNode.ParentNode.AppendChild(myOrderByNode);
212 | }
213 |
214 | return myOrderByNode;
215 | }
216 |
217 | #endregion
218 |
219 | #region Properties
220 |
221 | ///
222 | /// Gets or sets the Order By clause of the parsed sql.
223 | ///
224 | public string OrderByClause
225 | {
226 | get
227 | {
228 | #region Get the Order By xml node
229 |
230 | XmlNode myOrderByTagXmlNode = GetOrderByTagXmlNode(false);
231 | if (myOrderByTagXmlNode == null)
232 | return string.Empty;
233 |
234 | #endregion
235 |
236 | StringBuilder myStringBuilder = new StringBuilder();
237 | XmlNodesToText(myStringBuilder, myOrderByTagXmlNode.ChildNodes);
238 | return myStringBuilder.ToString();
239 | }
240 | set
241 | {
242 | if (string.IsNullOrEmpty(value))
243 | {
244 | #region Remove the Order By xml node
245 |
246 | XmlNode myOrderByXmlNode = GetOrderByTagXmlNode(false);
247 | if (myOrderByXmlNode != null)
248 | myOrderByXmlNode.ParentNode.RemoveChild(myOrderByXmlNode);
249 |
250 | #endregion
251 | }
252 | else
253 | {
254 | #region Modify the Order By xml node
255 |
256 | XmlNode myOrderByXmlNode = GetOrderByTagXmlNode(true);
257 |
258 | ClearXmlNode(myOrderByXmlNode);
259 |
260 | TagBase myOrderByTag = TagXmlNodeToTag(myOrderByXmlNode);
261 |
262 | ParseBlock(myOrderByXmlNode, myOrderByTag, value, 0);
263 |
264 | #endregion
265 | }
266 | }
267 | }
268 |
269 | #endregion
270 |
271 | #endregion
272 | }
273 |
274 | #endregion
275 | }
276 |
--------------------------------------------------------------------------------
/SqlParser/ClassDiagram.cd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | ForUpdateTag.cs
8 | AAAAAAAAAAAAAAEAAIAAgAQAAgAAAAAAAAAAAABAAAA=
9 |
10 |
11 |
12 |
13 |
14 | ForUpdateTag.cs
15 | AAAAAAAAAAAAAAAAAIAAAAQAAgAAAAAAAAAAAAAAAAA=
16 |
17 |
18 |
19 |
20 |
21 | FromTag.cs
22 | AAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAABAAAA=
23 |
24 |
25 |
26 |
27 |
28 | FromTag.cs
29 | AAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA=
30 |
31 |
32 |
33 |
34 |
35 | GroupByTag.cs
36 | AAAAAAAAAAAAAAEAAIAAgAQAAgAAAAAAAAAAAABAAAA=
37 |
38 |
39 |
40 |
41 |
42 | GroupByTag.cs
43 | AAAAAAAAAAAAAAAAAIAAAAQAAgAAAAAAAAAAAAAAAAA=
44 |
45 |
46 |
47 |
48 |
49 | OrderByTag.cs
50 | AAAAAAAAAAAAAAEAAIAAgAQAAgAAAAAAAAAAAABAAAA=
51 |
52 |
53 |
54 |
55 |
56 | OrderByTag.cs
57 | AAAAAAAAAAAAAAAAAIAAAAQAAgAAAAAAAAAAAAAAAAA=
58 |
59 |
60 |
61 |
62 |
63 | QuotedIdentifierTag.cs
64 | AAQAACAAEAAAAAAAICAAAAAAAAAAAAAAAAAAAABAAAA=
65 |
66 |
67 |
68 |
69 |
70 | QuotedIdentifierTag.cs
71 | AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
72 |
73 |
74 |
75 |
76 |
77 | SelectTag.cs
78 | AAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAABAAAA=
79 |
80 |
81 |
82 |
83 |
84 | SelectTag.cs
85 | AAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA=
86 |
87 |
88 |
89 |
90 |
91 | SimpleOneWordTag.cs
92 | IAQQACAAEAAAAAAAACAAAAQEAAAAAAAAABAAAAAAAAA=
93 |
94 |
95 |
96 |
97 |
98 | SimpleOneWordTag.cs
99 | AAAAAgAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA=
100 |
101 |
102 |
103 |
104 |
105 | SimpleTwoWordTag.cs
106 | AAAQACAAAAAAAAAAAIAAAAAAAgAAAAAAAAAAAAAAAAA=
107 |
108 |
109 |
110 |
111 |
112 | SimpleTwoWordTag.cs
113 | AAAAAgAAAAAAAAAAAIAAAAAAAgAAAAAAAAAAAAAAAAA=
114 |
115 |
116 |
117 |
118 |
119 | StartWith.cs
120 | AAAAAAAAAAAAAAEAAIAAgAQAAgAAAAAAAAAAAABAAAA=
121 |
122 |
123 |
124 |
125 |
126 | StartWith.cs
127 | AAAAAAAAAAAAAAAAAIAAAAQAAgAAAAAAAAAAAAAAAAA=
128 |
129 |
130 |
131 |
132 |
133 | StringLiteralTag.cs
134 | AAQAACAAEAAAAAAAICAAAAAAAAAAAAAAAAAAAABAAAA=
135 |
136 |
137 |
138 |
139 |
140 | StringLiteralTag.cs
141 | AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
142 |
143 |
144 |
145 |
146 |
147 | TagBase.cs
148 | AAQgACAAEAAAIEAAASAAAAIACAACAAAAAxEgBAAAICA=
149 |
150 |
151 |
152 |
153 |
154 | TagBase.cs
155 | AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
156 |
157 |
158 |
159 |
160 |
161 | WhereTag.cs
162 | AAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAABAAAA=
163 |
164 |
165 |
166 |
167 |
168 | WhereTag.cs
169 | AAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA=
170 |
171 |
172 |
173 |
174 |
175 | BracesTag.cs
176 | AAQAACAQEAAAAgAAICAAAAAAAAAAAAAAAABAAABAAAA=
177 |
178 |
179 |
180 |
181 |
182 | BracesTag.cs
183 | AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
184 |
185 |
186 |
--------------------------------------------------------------------------------
/SqlParser/TagBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Xml;
3 | using System.Text;
4 |
5 | namespace Parser
6 | {
7 | #region TagBase
8 |
9 | ///
10 | /// The base class for all the tags.
11 | ///
12 | public abstract class TagBase
13 | {
14 | #region Fields
15 |
16 | ///
17 | /// The value of the IsInitialized property.
18 | ///
19 | private bool fIsInitialized = false;
20 |
21 | ///
22 | /// The value of the HasContents property.
23 | ///
24 | private bool fHasContents = false;
25 |
26 | ///
27 | /// The value of the Value property.
28 | ///
29 | private string fValue;
30 |
31 | ///
32 | /// The value of the Parser property.
33 | ///
34 | private ParserBase fParser;
35 |
36 | #endregion
37 |
38 | #region Methods
39 |
40 | #region Initialization
41 |
42 | ///
43 | /// Reads the tag at the specified position in the specified word and separator array.
44 | ///
45 | ///
46 | /// The parent tag of this tag. This argument is used to determine
47 | /// the end of the tag (it can be the end of the parent tag).
48 | ///
49 | ///
50 | /// The position after the tag (at which to continue reading).
51 | ///
52 | public int InitializeFromText(ParserBase parser, string text, int position, TagBase parentTag)
53 | {
54 | #region Check the arguments
55 |
56 | if (parser == null)
57 | throw new ArgumentNullException("parser");
58 |
59 | #endregion
60 |
61 | int myResult = InitializeCoreFromText(parser, text, position, parentTag);
62 |
63 | IsInitialized = true;
64 |
65 | return myResult;
66 | }
67 |
68 | ///
69 | /// Reads the tag at the specified position in the specified word and separator array.
70 | ///
71 | ///
72 | /// The parent tag of this tag. This argument is used to determine
73 | /// the end of the tag (it can be the end of the parent tag).
74 | ///
75 | ///
76 | /// The position after the tag (at which to continue reading).
77 | ///
78 | protected abstract int InitializeCoreFromText(ParserBase parser, string text, int position, TagBase parentTag);
79 |
80 | ///
81 | /// Reads the tag from the specified data.
82 | ///
83 | public void InitializeFromData(ParserBase parser, string value, bool hasContents)
84 | {
85 | #region Check the arguments
86 |
87 | if (parser == null)
88 | throw new ArgumentNullException("parser");
89 |
90 | #endregion
91 |
92 | InitializeFromDataCore(parser, value, hasContents);
93 |
94 | IsInitialized = true;
95 | }
96 |
97 | ///
98 | /// Reads the tag from the specified data.
99 | ///
100 | protected virtual void InitializeFromDataCore(ParserBase parser, string value, bool hasContents)
101 | {
102 | Parser = parser;
103 |
104 | Value = value;
105 |
106 | HasContents = hasContents;
107 |
108 | IsInitialized = true;
109 | }
110 |
111 | #endregion
112 |
113 | #region Attributes-Related (Static)
114 |
115 | ///
116 | /// Returns the type of the specified tag (its identifier).
117 | /// This method is used by the Type property.
118 | ///
119 | public static string GetTagType(Type tag)
120 | {
121 | #region Check the arguments
122 |
123 | if (tag == null)
124 | throw new ArgumentNullException("tag");
125 |
126 | #endregion
127 |
128 | object[] myTagTypeAttributes = tag.GetCustomAttributes(typeof(TagTypeAttribute), true);
129 |
130 | if (myTagTypeAttributes == null || myTagTypeAttributes.Length == 0)
131 | throw new Exception("Cannot find a tag type attribute.");
132 |
133 | if (myTagTypeAttributes.Length > 1)
134 | throw new Exception("Ambiguous tag type.");
135 |
136 | return (myTagTypeAttributes[0] as TagTypeAttribute).Type;
137 | }
138 |
139 | ///
140 | /// Returns the match attribute of the specified class.
141 | /// This attribute is used to identify a tag in a text.
142 | ///
143 | public static MatchTagAttributeBase GetTagMatchAttribute(Type tag)
144 | {
145 | #region Check the arguments
146 |
147 | if (tag == null)
148 | throw new ArgumentNullException("tag");
149 |
150 | #endregion
151 |
152 | object[] myMatchTagAttributes = tag.GetCustomAttributes(typeof(MatchTagAttributeBase), true);
153 |
154 | if (myMatchTagAttributes == null || myMatchTagAttributes.Length == 0)
155 | throw new Exception("Cannot find a match tag attribute.");
156 |
157 | if (myMatchTagAttributes.Length > 1)
158 | throw new Exception("Ambiguous match tag.");
159 |
160 | return myMatchTagAttributes[0] as MatchTagAttributeBase;
161 | }
162 |
163 | #endregion
164 |
165 | #region Common
166 |
167 | ///
168 | /// Returns a value indicating whether there is the tag ending
169 | /// at the specified position.
170 | ///
171 | ///
172 | /// If this value is less than zero, then there is no ending; otherwise the
173 | /// position after ending is returned.
174 | ///
175 | public virtual int MatchEnd(string text, int position)
176 | {
177 | CheckInitialized();
178 |
179 | throw new System.NotImplementedException();
180 | }
181 |
182 | ///
183 | /// Writes the start of the tag.
184 | ///
185 | public abstract void WriteStart(StringBuilder output);
186 |
187 | ///
188 | /// Writes the end of the tag.
189 | ///
190 | public virtual void WriteEnd(StringBuilder output)
191 | {
192 | CheckInitialized();
193 | }
194 |
195 | ///
196 | /// Checks whether the tag is initialized, and throws an exception if not. This method should be called before a tag porperty or method is accessed.
197 | ///
198 | protected void CheckInitialized()
199 | {
200 | if (!IsInitialized)
201 | throw new Exception("Tag is not initialized.");
202 | }
203 |
204 | #endregion
205 |
206 | #endregion
207 |
208 | #region Properties
209 |
210 | ///
211 | /// Returns the type of the tag (its identifier).
212 | ///
213 | public string Type
214 | {
215 | get
216 | {
217 | return GetTagType(GetType());
218 | }
219 | }
220 |
221 | ///
222 | /// The value of the tag (it can be the text of a string literal for example).
223 | ///
224 | public string Value
225 | {
226 | get
227 | {
228 | CheckInitialized();
229 |
230 | return fValue;
231 | }
232 | protected set
233 | {
234 | fValue = value;
235 | }
236 | }
237 |
238 | ///
239 | /// Gets a value indicating whether this tag has contents to be parsed.
240 | ///
241 | public virtual bool HasContents
242 | {
243 | get
244 | {
245 | CheckInitialized();
246 |
247 | return fHasContents;
248 | }
249 | protected set
250 | {
251 | fHasContents = value;
252 | }
253 | }
254 |
255 | ///
256 | /// Inidicates whether the string end can be treated as the end of the tag.
257 | ///
258 | public virtual bool CanTerminateByStringEnd
259 | {
260 | get
261 | {
262 | CheckInitialized();
263 |
264 | return false;
265 | }
266 | }
267 |
268 | ///
269 | /// Indicates whether the tag has been initialized.
270 | ///
271 | protected bool IsInitialized
272 | {
273 | get
274 | {
275 | return fIsInitialized;
276 | }
277 | private set
278 | {
279 | fIsInitialized = value;
280 | }
281 | }
282 |
283 | ///
284 | /// The parser which has created this instance.
285 | ///
286 | public ParserBase Parser
287 | {
288 | get
289 | {
290 | CheckInitialized();
291 |
292 | return fParser;
293 | }
294 | protected set
295 | {
296 | fParser = value;
297 | }
298 | }
299 |
300 | #endregion
301 | }
302 |
303 | #endregion
304 |
305 | #region MatchTagAttributeBase
306 |
307 | ///
308 | /// This attribute is used to determine whether there is certain tag
309 | /// at a position in a text.
310 | ///
311 | public abstract class MatchTagAttributeBase : Attribute
312 | {
313 | public abstract bool Match(string text, int position);
314 | }
315 |
316 | #endregion
317 |
318 | #region TagTypeAttribute
319 |
320 | ///
321 | /// This attribute is used to determine the name (identifier) of a tag.
322 | ///
323 | public sealed class TagTypeAttribute : Attribute
324 | {
325 | #region Fields
326 |
327 | private string fType;
328 |
329 | #endregion
330 |
331 | #region Methods
332 |
333 | public TagTypeAttribute(string type)
334 | {
335 | Type = type;
336 | }
337 |
338 | #endregion
339 |
340 | #region Properties
341 |
342 | public string Type
343 | {
344 | get
345 | {
346 | return fType;
347 | }
348 | private set
349 | {
350 | fType = value;
351 | }
352 | }
353 |
354 | #endregion
355 | }
356 |
357 | #endregion
358 | }
--------------------------------------------------------------------------------
/SqlParser/ParserBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Xml;
4 |
5 | namespace Parser
6 | {
7 | #region ParserBase
8 |
9 | ///
10 | /// An abstract class which is used as the base class for parsers.
11 | /// It contains basic methods which allow you to create a logical tree
12 | /// from a document.
13 | ///
14 | public abstract class ParserBase
15 | {
16 | #region Consts
17 |
18 | ///
19 | /// The name of the Value xml attribute.
20 | ///
21 | protected const string cValueXmlAttributeName = "Value";
22 |
23 | ///
24 | /// The name of the Tag Type xml attribute.
25 | ///
26 | protected const string cTagTypeXmlAttributeName = "Type";
27 |
28 | ///
29 | /// The name of the root node in the xml representation of a parsed text.
30 | ///
31 | protected const string cRootXmlNodeName = "ParsedDocument";
32 |
33 | ///
34 | /// The name of the Tag xml node.
35 | ///
36 | protected const string cTagXmlNodeName = "Tag";
37 |
38 | ///
39 | /// The name of the Text xml node.
40 | ///
41 | protected const string cTextXmlNodeName = "Text";
42 |
43 | ///
44 | /// The white space text (is used when adding white
45 | /// spaces between text elements).
46 | ///
47 | public const string cWhiteSpace = " ";
48 |
49 | ///
50 | /// The new line string.
51 | ///
52 | public const string cNewLine = "\r\n";
53 |
54 | #endregion
55 |
56 | #region Fields
57 |
58 | ///
59 | /// The tree representation of a parsed document as an xml document.
60 | ///
61 | private XmlDocument fParsedDocument;
62 |
63 | #endregion
64 |
65 | #region Methods
66 |
67 | ///
68 | /// Parses the specified text.
69 | ///
70 | public void Parse(string text)
71 | {
72 | #region Check the arguments
73 |
74 | if (text == null)
75 | throw new ArgumentNullException("text");
76 |
77 | #endregion
78 |
79 | fParsedDocument = new XmlDocument();
80 | XmlNode myRootNode = fParsedDocument.CreateElement(cRootXmlNodeName);
81 | fParsedDocument.AppendChild(myRootNode);
82 |
83 | try
84 | {
85 | ParseBlock(myRootNode, null, text, 0);
86 | }
87 | catch
88 | {
89 | fParsedDocument = null;
90 | throw;
91 | }
92 |
93 | // m_ParsedDocument.Save(@"D:\Temp\ParserTest.xml");
94 | }
95 |
96 | ///
97 | /// Parses the specified block of a text.
98 | ///
99 | ///
100 | /// Returns the end position of the parsed block.
101 | ///
102 | protected int ParseBlock(XmlNode parentNode, TagBase parentTag, string text, int position)
103 | {
104 | #region Check the arguments
105 |
106 | if (parentNode == null)
107 | throw new ArgumentNullException("parentNode");
108 |
109 | CheckTextAndPositionArguments(text, position);
110 |
111 | #endregion
112 |
113 | while (position < text.Length)
114 | {
115 | if (IsSkipWhiteSpace)
116 | SkipWhiteSpace(text, ref position);
117 |
118 | if (position == text.Length)
119 | break;
120 |
121 | #region Read the parent tag ending
122 |
123 | if (parentTag != null)
124 | {
125 | int myParentTagEndingEndPosition = parentTag.MatchEnd(text, position);
126 | if (myParentTagEndingEndPosition >= 0)
127 | {
128 | position = myParentTagEndingEndPosition;
129 | return position;
130 | }
131 | }
132 |
133 | #endregion
134 |
135 | Type myTagType = IsTag(text, position);
136 | if (myTagType != null)
137 | {
138 | #region Read a tag
139 |
140 | #region Create the tag class instance
141 |
142 | TagBase myTag = Activator.CreateInstance(myTagType) as TagBase;
143 | position = myTag.InitializeFromText(this, text, position, parentTag);
144 |
145 | #endregion
146 |
147 | #region Create an xml node for the tag
148 |
149 | XmlNode myTagXmlNode = CreateTagXmlNode(myTag);
150 | parentNode.AppendChild(myTagXmlNode);
151 |
152 | #endregion
153 |
154 | if (myTag.HasContents)
155 | position = ParseBlock(myTagXmlNode, myTag, text, position);
156 |
157 | #endregion
158 | }
159 | else
160 | {
161 | #region Read text
162 |
163 | string myText = ReadWordOrSeparator(text, ref position, !IsSkipWhiteSpace);
164 | parentNode.AppendChild(CreateTextXmlNode(myText));
165 |
166 | #endregion
167 | }
168 | }
169 |
170 | if (parentTag != null && !parentTag.CanTerminateByStringEnd)
171 | throw new Exception("Invalid format");
172 |
173 | return position;
174 | }
175 |
176 | ///
177 | /// Checks whether there is a tag in the text at the specified position, and returns its type.
178 | ///
179 | protected Type IsTag(string text, int position)
180 | {
181 | foreach (Type myTagType in Tags)
182 | {
183 | MatchTagAttributeBase myMatchTagAttribute = TagBase.GetTagMatchAttribute(myTagType);
184 | if (myMatchTagAttribute.Match(text, position))
185 | return myTagType;
186 | }
187 |
188 | return null;
189 | }
190 |
191 | ///
192 | /// Creates an xml node for the specified tag.
193 | ///
194 | protected XmlNode CreateTagXmlNode(TagBase tag)
195 | {
196 | #region Check the arguments
197 |
198 | if (tag == null)
199 | throw new ArgumentNullException();
200 |
201 | #endregion
202 |
203 | CheckXmlDocInitialized();
204 |
205 | XmlElement myTagNode = fParsedDocument.CreateElement(cTagXmlNodeName);
206 |
207 | XmlAttribute myTypeAttribute = fParsedDocument.CreateAttribute(cTagTypeXmlAttributeName);
208 | myTypeAttribute.Value = tag.Type;
209 | myTagNode.Attributes.Append(myTypeAttribute);
210 |
211 | if (tag.Value != null)
212 | {
213 | XmlAttribute myValueAttribute = fParsedDocument.CreateAttribute(cValueXmlAttributeName);
214 | myValueAttribute.Value = tag.Value;
215 | myTagNode.Attributes.Append(myValueAttribute);
216 | }
217 |
218 | return myTagNode;
219 | }
220 |
221 | ///
222 | /// Creates an xml node for the specified text.
223 | ///
224 | protected XmlNode CreateTextXmlNode(string text)
225 | {
226 | #region Check the arguments
227 |
228 | if (text == null)
229 | throw new ArgumentNullException("text");
230 |
231 | #endregion
232 |
233 | CheckXmlDocInitialized();
234 |
235 | XmlElement myTextNode = fParsedDocument.CreateElement(cTextXmlNodeName);
236 |
237 | XmlAttribute myValueAttribute = fParsedDocument.CreateAttribute(cValueXmlAttributeName);
238 | myValueAttribute.Value = text;
239 | myTextNode.Attributes.Append(myValueAttribute);
240 |
241 | return myTextNode;
242 | }
243 |
244 | ///
245 | /// Skips the white space symbols located at the specified position.
246 | ///
247 | public static void SkipWhiteSpace(string text, ref int position)
248 | {
249 | #region Check the parameters
250 |
251 | CheckTextAndPositionArguments(text, position);
252 |
253 | #endregion
254 |
255 | while (position < text.Length)
256 | {
257 | if (!char.IsWhiteSpace(text, position))
258 | break;
259 | position++;
260 | }
261 | }
262 |
263 | ///
264 | /// Reads a single word or separator at the specified position.
265 | ///
266 | public static string ReadWordOrSeparator(string text, ref int position, bool treatWhiteSpaceAsSeparator)
267 | {
268 | #region Check the parameters
269 |
270 | CheckTextAndPositionArguments(text, position);
271 |
272 | #endregion
273 |
274 | int myStartPosition = position;
275 |
276 | while (position < text.Length)
277 | {
278 | #region Check is white space
279 |
280 | if (char.IsWhiteSpace(text, position))
281 | {
282 | if (position == myStartPosition && treatWhiteSpaceAsSeparator)
283 | {
284 | if (position + cNewLine.Length <= text.Length && text.Substring(position, cNewLine.Length) == cNewLine)
285 | position += cNewLine.Length;
286 | else
287 | position += 1;
288 | }
289 | break;
290 | }
291 |
292 | #endregion
293 |
294 | #region Check is separator
295 |
296 | if (!char.IsLetterOrDigit(text, position) && text[position] != '_')
297 | {
298 | if (position == myStartPosition)
299 | position++;
300 | break;
301 | }
302 |
303 | #endregion
304 |
305 | position++;
306 | }
307 |
308 | if (position == myStartPosition)
309 | return string.Empty;
310 |
311 | return text.Substring(myStartPosition, position - myStartPosition);
312 | }
313 |
314 | ///
315 | /// Checks the text and position parameters.
316 | ///
317 | public static void CheckTextAndPositionArguments(string text, int position)
318 | {
319 | #region Check the parameters
320 |
321 | if (text == null)
322 | throw new ArgumentNullException("text");
323 |
324 | if (position < 0 || position >= text.Length)
325 | throw new ArgumentOutOfRangeException("position");
326 |
327 | #endregion
328 | }
329 |
330 | ///
331 | /// Checks whether the m_ParsedDocument is initialized.
332 | ///
333 | protected void CheckXmlDocInitialized()
334 | {
335 | if (fParsedDocument == null)
336 | throw new Exception("Xml document is not initialized");
337 | }
338 |
339 | ///
340 | /// Returns the text string processed by the parser.
341 | ///
342 | public string ToText()
343 | {
344 | CheckXmlDocInitialized();
345 |
346 | StringBuilder myStringBuilder = new StringBuilder();
347 |
348 | XmlNodesToText(myStringBuilder, fParsedDocument.ChildNodes[0].ChildNodes);
349 |
350 | return myStringBuilder.ToString();
351 | }
352 |
353 | ///
354 | /// Converts the specified xml node collection to the text.
355 | ///
356 | protected void XmlNodesToText(StringBuilder output, XmlNodeList nodes)
357 | {
358 | #region Check arguments
359 |
360 | if (nodes == null)
361 | throw new ArgumentNullException("nodes");
362 |
363 | if (output == null)
364 | throw new ArgumentNullException("output");
365 |
366 | #endregion
367 |
368 | foreach (XmlNode myNode in nodes)
369 | XmlNodeToText(output, myNode);
370 | }
371 |
372 | ///
373 | /// Converts the specified xml node to text.
374 | ///
375 | protected void XmlNodeToText(StringBuilder output, XmlNode node)
376 | {
377 | #region Check arguments
378 |
379 | if (node == null)
380 | throw new ArgumentNullException("node");
381 |
382 | if (output == null)
383 | throw new ArgumentNullException("output");
384 |
385 | #endregion
386 |
387 | if (IsTagXmlNode(node))
388 | {
389 | TagXmlNodeToText(output, node);
390 | }
391 | else if (IsTextXmlNode(node))
392 | {
393 | output.Append(GetTextNodeText(node));
394 |
395 | if (IsSkipWhiteSpace)
396 | output.Append(cWhiteSpace);
397 | }
398 | else
399 | {
400 | throw new Exception("Unrecognized xml node.");
401 | }
402 |
403 | //m_ParsedDocument.Save(@"D:\Temp\testparser.xml");
404 | }
405 |
406 | ///
407 | /// Determines whether the specified node is a tag node.
408 | ///
409 | protected bool IsTagXmlNode(XmlNode node)
410 | {
411 | #region Check arguments
412 |
413 | if (node == null)
414 | throw new ArgumentNullException("node");
415 |
416 | #endregion
417 |
418 | return node.Name == cTagXmlNodeName;
419 | }
420 |
421 | ///
422 | /// Determines whether the specified node is a text node.
423 | ///
424 | protected bool IsTextXmlNode(XmlNode node)
425 | {
426 | #region Check arguments
427 |
428 | if (node == null)
429 | throw new ArgumentNullException("node");
430 |
431 | #endregion
432 |
433 | return node.Name == cTextXmlNodeName;
434 | }
435 |
436 | ///
437 | /// Returns the text stored in the text node.
438 | ///
439 | protected string GetTextNodeText(XmlNode node)
440 | {
441 | string myValue = GetXmlNodeValue(node);
442 | if (myValue == null)
443 | throw new Exception("Cannot get text node's value.");
444 |
445 | return myValue;
446 | }
447 |
448 | ///
449 | /// Retrieves the value of the specified tag xml node.
450 | ///
451 | protected string GetXmlNodeValue(XmlNode node)
452 | {
453 | #region Check arguments
454 |
455 | if (node == null)
456 | throw new ArgumentNullException("node");
457 |
458 | #endregion
459 |
460 | XmlAttribute myValueXmlAttribute = node.Attributes[cValueXmlAttributeName];
461 | if (myValueXmlAttribute == null)
462 | return null;
463 |
464 | return myValueXmlAttribute.Value;
465 | }
466 |
467 | ///
468 | /// Converts the specified tag xml node to text.
469 | ///
470 | private void TagXmlNodeToText(StringBuilder output, XmlNode node)
471 | {
472 | #region Check arguments
473 |
474 | if (node == null)
475 | throw new ArgumentNullException("node");
476 |
477 | if (output == null)
478 | throw new ArgumentNullException("output");
479 |
480 | #endregion
481 |
482 | TagBase myTag = TagXmlNodeToTag(node);
483 |
484 | myTag.WriteStart(output);
485 |
486 | if (IsSkipWhiteSpace)
487 | output.Append(cWhiteSpace);
488 |
489 | if (node.ChildNodes.Count > 0)
490 | XmlNodesToText(output, node.ChildNodes);
491 |
492 | myTag.WriteEnd(output);
493 |
494 | if (IsSkipWhiteSpace)
495 | output.Append(cWhiteSpace);
496 | }
497 |
498 | ///
499 | /// Converts the specified tag xml node into a tag.
500 | ///
501 | protected TagBase TagXmlNodeToTag(XmlNode node)
502 | {
503 | #region Check arguments
504 |
505 | if (node == null)
506 | throw new ArgumentNullException("node");
507 |
508 | #endregion
509 |
510 | #region Get tag parameters
511 |
512 | XmlAttribute myTagTypeXmlAttribute = node.Attributes[cTagTypeXmlAttributeName];
513 | if (myTagTypeXmlAttribute == null)
514 | throw new Exception("Cannot find the tag type attribute");
515 | string myTagType = myTagTypeXmlAttribute.Value;
516 |
517 | XmlAttribute myValueXmlAttribute = node.Attributes[cValueXmlAttributeName];
518 | string myTagValue;
519 | if (myValueXmlAttribute == null)
520 | myTagValue = null;
521 | else
522 | myTagValue = myValueXmlAttribute.Value;
523 |
524 | #endregion
525 |
526 | return GetTagFromType(myTagType, myTagValue, node.ChildNodes.Count > 0);
527 | }
528 |
529 | ///
530 | /// Retrurns the tag instance from its type and value.
531 | ///
532 | protected TagBase GetTagFromType(string type, string value, bool hasContents)
533 | {
534 | foreach (Type myTagType in Tags)
535 | {
536 | string myType = TagBase.GetTagType(myTagType);
537 | if (string.Compare(myType, type, true) == 0)
538 | {
539 | TagBase myTag = Activator.CreateInstance(myTagType) as TagBase;
540 | myTag.InitializeFromData(this, value, hasContents);
541 | return myTag;
542 | }
543 | }
544 |
545 | throw new Exception(string.Format("Tag cannot be found: {0}", type));
546 | }
547 |
548 | ///
549 | /// Removes all the sub nodes from the specified node.
550 | ///
551 | protected static void ClearXmlNode(XmlNode node)
552 | {
553 | #region Check arguments
554 |
555 | if (node == null)
556 | throw new ArgumentNullException("node");
557 |
558 | #endregion
559 |
560 | for (int myChildIndex = node.ChildNodes.Count - 1; myChildIndex >= 0; myChildIndex--)
561 | node.RemoveChild(node.ChildNodes[myChildIndex]);
562 | }
563 |
564 | ///
565 | /// Returns how many continuous specified strings are before of the specified
566 | /// position in the specified text
567 | ///
568 | public static int CountStringsBefore(string text, int position, string @string)
569 | {
570 | CheckTextAndPositionArguments(text, position);
571 |
572 | #region Count the Strings before
573 |
574 | int myStringsBeforeCount = 0;
575 | int myPrevPosition = position - @string.Length;
576 | while (myPrevPosition >= 0)
577 | {
578 | // If it is not the specified string prefix
579 | if (string.Compare(text, myPrevPosition, @string, 0, @string.Length, true) != 0)
580 | break;
581 |
582 | myStringsBeforeCount++;
583 | myPrevPosition -= @string.Length;
584 | }
585 |
586 | #endregion
587 |
588 | return myStringsBeforeCount;
589 | }
590 |
591 | #endregion
592 |
593 | #region Properties
594 |
595 | ///
596 | /// Indicates whether the white space is considered as a non-valuable
597 | /// character.
598 | ///
599 | protected abstract bool IsSkipWhiteSpace { get; }
600 |
601 | ///
602 | /// The list of all available tags.
603 | ///
604 | protected abstract Type[] Tags { get; }
605 |
606 | ///
607 | /// Gets the parsed document in xml format.
608 | ///
609 | protected XmlDocument ParsedDocument
610 | {
611 | get
612 | {
613 | CheckXmlDocInitialized();
614 |
615 | return fParsedDocument;
616 | }
617 | }
618 |
619 | #endregion
620 | }
621 |
622 | #endregion
623 | }
624 |
--------------------------------------------------------------------------------