From 82e8849892e53f928f7193affcbc3e620dea9349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaros=C5=82aw=20Dutka?= Date: Wed, 12 Jun 2024 13:55:39 +0200 Subject: [PATCH 1/2] Add option to parse DTD. --- README.md | 2 ++ XmlSchemaClassGenerator.Console/Program.cs | 3 +++ XmlSchemaClassGenerator/Generator.cs | 8 +++++++- XmlSchemaClassGenerator/GeneratorConfiguration.cs | 5 +++++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6576021..0a0d6a3 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,8 @@ Options: --uc, --unionCommonType generate a common type for unions if possible ( default is false) + --dtd, --allowDtdParse + allow DTD parsing (default is false) ``` For use from code use the [library NuGet package](https://www.nuget.org/packages/XmlSchemaClassGenerator-beta/): diff --git a/XmlSchemaClassGenerator.Console/Program.cs b/XmlSchemaClassGenerator.Console/Program.cs index 5edc1f4..6aee3ce 100644 --- a/XmlSchemaClassGenerator.Console/Program.cs +++ b/XmlSchemaClassGenerator.Console/Program.cs @@ -66,6 +66,7 @@ static int Main(string[] args) var unionCommonType = false; var separateNamespaceHierarchy = false; var serializeEmptyCollections = false; + var allowDtdParse = false; var options = new OptionSet { { "h|help", "show this message and exit", v => showHelp = v != null }, @@ -160,6 +161,7 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l { "ca|commandArgs", "generate a comment with the exact command line arguments that were used to generate the source code (default is true)", v => generateCommandLineArgs = v != null }, { "uc|unionCommonType", "generate a common type for unions if possible (default is false)", v => unionCommonType = v != null }, { "ec|serializeEmptyCollections", "serialize empty collections (default is false)", v => serializeEmptyCollections = v != null }, + { "dtd|allowDtdParse", "allows dtd parse (default is false)", v => allowDtdParse = v != null }, }; var globsAndUris = options.Parse(args); @@ -248,6 +250,7 @@ A file name may be given by appending a pipe sign (|) followed by a file name (l MapUnionToWidestCommonType = unionCommonType, SeparateNamespaceHierarchy = separateNamespaceHierarchy, SerializeEmptyCollections = serializeEmptyCollections, + AllowDtdParse = allowDtdParse }; if (nameSubstituteMap.Any()) diff --git a/XmlSchemaClassGenerator/Generator.cs b/XmlSchemaClassGenerator/Generator.cs index c543b1c..b9d96f5 100644 --- a/XmlSchemaClassGenerator/Generator.cs +++ b/XmlSchemaClassGenerator/Generator.cs @@ -342,6 +342,12 @@ public bool SerializeEmptyCollections set { _configuration.SerializeEmptyCollections = value; } } + public bool AllowDtdParse + { + get { return _configuration.AllowDtdParse; } + set { _configuration.AllowDtdParse = value; } + } + public bool ValidationError { get; private set; } static Generator() @@ -352,7 +358,7 @@ static Generator() public void Generate(IEnumerable files) { var set = new XmlSchemaSet(); - var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore }; + var settings = new XmlReaderSettings { DtdProcessing = AllowDtdParse ? DtdProcessing.Parse : DtdProcessing.Ignore }; var readers = files.Select(f => XmlReader.Create(f, settings)); ValidationError = false; diff --git a/XmlSchemaClassGenerator/GeneratorConfiguration.cs b/XmlSchemaClassGenerator/GeneratorConfiguration.cs index 6cd6692..4541bc0 100644 --- a/XmlSchemaClassGenerator/GeneratorConfiguration.cs +++ b/XmlSchemaClassGenerator/GeneratorConfiguration.cs @@ -348,5 +348,10 @@ public void WriteLog(string message) /// Determines whether empty collections should be serialized as empty elements. Default is false. /// public bool SerializeEmptyCollections { get; set; } = false; + + /// + /// Allow DTD parsing. Default is false. + /// + public bool AllowDtdParse { get; set; } = false; } } From d6edab471bfdd193bfc6b30e0f9e319d89bc29c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaros=C5=82aw=20Dutka?= Date: Thu, 13 Jun 2024 22:53:12 +0200 Subject: [PATCH 2/2] Add option to parse DTD - Unit tests. --- XmlSchemaClassGenerator.Tests/XmlTests.cs | 97 +++++++++++++++++++---- XmlSchemaClassGenerator/Generator.cs | 21 ++++- 2 files changed, 101 insertions(+), 17 deletions(-) diff --git a/XmlSchemaClassGenerator.Tests/XmlTests.cs b/XmlSchemaClassGenerator.Tests/XmlTests.cs index 236f18f..dbd0a0b 100644 --- a/XmlSchemaClassGenerator.Tests/XmlTests.cs +++ b/XmlSchemaClassGenerator.Tests/XmlTests.cs @@ -61,25 +61,13 @@ private static IEnumerable ConvertXml(string name, IEnumerable x CollectionSettersMode = generatorPrototype.CollectionSettersMode, UseArrayItemAttribute = generatorPrototype.UseArrayItemAttribute, EnumAsString = generatorPrototype.EnumAsString, + AllowDtdParse = generatorPrototype.AllowDtdParse }; gen.CommentLanguages.Clear(); gen.CommentLanguages.UnionWith(generatorPrototype.CommentLanguages); - var set = new XmlSchemaSet(); - - foreach (var xsd in xsds) - { - using var stringReader = new StringReader(xsd); - var schema = XmlSchema.Read(stringReader, (s, e) => - { - throw new InvalidOperationException($"{e.Severity}: {e.Message}",e.Exception); - }); - - set.Add(schema); - } - - gen.Generate(set); + gen.Generate(xsds.Select(i => new StringReader(i))); return writer.Content; } @@ -3012,5 +3000,86 @@ public void SimpleInterface(bool generateInterface) Assert.Null(interfaceCommon); } } + + + [Fact] + public void TestAllowDtdParse() + { + const string xsd = @" + + + +]> + + + + + List of Profiles + + + + + + + + + + + +"; + var generator = new Generator + { + NamespaceProvider = new NamespaceProvider + { + GenerateNamespace = key => "Test" + }, + AllowDtdParse = true + }; + + var generatedType = ConvertXml(nameof(TestAllowDtdParse), xsd, generator).First(); + + Assert.Contains(@"public partial class ComplexType", generatedType); + Assert.Contains(@"[a-zA-Z0-9]+", generatedType); + } + + [Fact] + public void TestNotAllowDtdParse() + { + const string xsd = @" + + + +]> + + + + + List of Profiles + + + + + + + + + + + +"; + var generator = new Generator + { + NamespaceProvider = new NamespaceProvider + { + GenerateNamespace = key => "Test" + }, + AllowDtdParse = false + }; + + var exception = Assert.Throws(() => ConvertXml(nameof(TestNotAllowDtdParse), xsd, generator)); + Assert.Contains("Reference to undeclared entity 'lowalpha'", exception.Message); + } } } diff --git a/XmlSchemaClassGenerator/Generator.cs b/XmlSchemaClassGenerator/Generator.cs index b9d96f5..7e584d8 100644 --- a/XmlSchemaClassGenerator/Generator.cs +++ b/XmlSchemaClassGenerator/Generator.cs @@ -1,7 +1,7 @@ using System; using System.CodeDom; using System.Collections.Generic; -using System.Diagnostics; +using System.IO; using System.Linq; using System.Text; using System.Xml; @@ -356,10 +356,20 @@ static Generator() } public void Generate(IEnumerable files) + { + var settings = CreateSettings(); + Generate(files.Select(f => XmlReader.Create(f, settings))); + } + + public void Generate(IEnumerable streams) + { + var settings = CreateSettings(); + Generate(streams.Select(f => XmlReader.Create(f, settings))); + } + + public void Generate(IEnumerable readers) { var set = new XmlSchemaSet(); - var settings = new XmlReaderSettings { DtdProcessing = AllowDtdParse ? DtdProcessing.Parse : DtdProcessing.Ignore }; - var readers = files.Select(f => XmlReader.Create(f, settings)); ValidationError = false; @@ -413,5 +423,10 @@ public void Generate(XmlSchemaSet set) writer.Write(ns); } } + + private XmlReaderSettings CreateSettings() + { + return new XmlReaderSettings { DtdProcessing = AllowDtdParse ? DtdProcessing.Parse : DtdProcessing.Ignore }; + } } } \ No newline at end of file