Skip to content

Commit

Permalink
Merge pull request #514 from jaroslaw-dutka-external/feature/dtd-support
Browse files Browse the repository at this point in the history
Add option to parse DTD.
  • Loading branch information
mganss authored Jun 14, 2024
2 parents 59ba300 + d6edab4 commit a8983a9
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 17 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/):
Expand Down
3 changes: 3 additions & 0 deletions XmlSchemaClassGenerator.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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())
Expand Down
97 changes: 83 additions & 14 deletions XmlSchemaClassGenerator.Tests/XmlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,25 +61,13 @@ private static IEnumerable<string> ConvertXml(string name, IEnumerable<string> 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;
}
Expand Down Expand Up @@ -3012,5 +3000,86 @@ public void SimpleInterface(bool generateInterface)
Assert.Null(interfaceCommon);
}
}


[Fact]
public void TestAllowDtdParse()
{
const string xsd = @"<?xml version=""1.0"" encoding=""utf-8""?>
<!DOCTYPE schema [
<!ENTITY lowalpha ""a-z"">
<!ENTITY hialpha ""A-Z"">
<!ENTITY digit ""0-9"">
]>
<xs:schema xmlns:xs=""http://www.w3.org/2001/XMLSchema"">
<xs:simpleType name=""CodecsType"">
<xs:annotation>
<xs:documentation xml:lang=""en"">
List of Profiles
</xs:documentation>
</xs:annotation>
<xs:restriction base=""xs:string"">
<xs:pattern value=""[&lowalpha;&hialpha;&digit;]+""/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name=""ComplexType"">
<xs:attribute name=""codecs"" type=""CodecsType""/>
</xs:complexType>
</xs:schema>
";
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 = @"<?xml version=""1.0"" encoding=""utf-8""?>
<!DOCTYPE schema [
<!ENTITY lowalpha ""a-z"">
<!ENTITY hialpha ""A-Z"">
<!ENTITY digit ""0-9"">
]>
<xs:schema xmlns:xs=""http://www.w3.org/2001/XMLSchema"">
<xs:simpleType name=""CodecsType"">
<xs:annotation>
<xs:documentation xml:lang=""en"">
List of Profiles
</xs:documentation>
</xs:annotation>
<xs:restriction base=""xs:string"">
<xs:pattern value=""[&lowalpha;&hialpha;&digit;]+""/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name=""ComplexType"">
<xs:attribute name=""codecs"" type=""CodecsType""/>
</xs:complexType>
</xs:schema>
";
var generator = new Generator
{
NamespaceProvider = new NamespaceProvider
{
GenerateNamespace = key => "Test"
},
AllowDtdParse = false
};

var exception = Assert.Throws<XmlException>(() => ConvertXml(nameof(TestNotAllowDtdParse), xsd, generator));
Assert.Contains("Reference to undeclared entity 'lowalpha'", exception.Message);
}
}
}
27 changes: 24 additions & 3 deletions XmlSchemaClassGenerator/Generator.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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()
Expand All @@ -350,10 +356,20 @@ static Generator()
}

public void Generate(IEnumerable<string> files)
{
var settings = CreateSettings();
Generate(files.Select(f => XmlReader.Create(f, settings)));
}

public void Generate(IEnumerable<TextReader> streams)
{
var settings = CreateSettings();
Generate(streams.Select(f => XmlReader.Create(f, settings)));
}

public void Generate(IEnumerable<XmlReader> readers)
{
var set = new XmlSchemaSet();
var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore };
var readers = files.Select(f => XmlReader.Create(f, settings));

ValidationError = false;

Expand Down Expand Up @@ -407,5 +423,10 @@ public void Generate(XmlSchemaSet set)
writer.Write(ns);
}
}

private XmlReaderSettings CreateSettings()
{
return new XmlReaderSettings { DtdProcessing = AllowDtdParse ? DtdProcessing.Parse : DtdProcessing.Ignore };
}
}
}
5 changes: 5 additions & 0 deletions XmlSchemaClassGenerator/GeneratorConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -348,5 +348,10 @@ public void WriteLog(string message)
/// Determines whether empty collections should be serialized as empty elements. Default is false.
/// </summary>
public bool SerializeEmptyCollections { get; set; } = false;

/// <summary>
/// Allow DTD parsing. Default is false.
/// </summary>
public bool AllowDtdParse { get; set; } = false;
}
}

0 comments on commit a8983a9

Please sign in to comment.