9

I have an XML file with no DOCTYPE declaration that I would like to validate with an external DTD upon reading.

Dim x_set As Xml.XmlReaderSettings = New Xml.XmlReaderSettings()
x_set.XmlResolver = Nothing
x_set.CheckCharacters = False
x_set.ProhibitDtd = False
x = XmlTextReader.Create(sChemin, x_set)

How do you set the path for that external DTD? How do you validate?

Vincent
  • 22,366
  • 18
  • 58
  • 61

3 Answers3

16

I have used the following function successfully before, which should be easy to adapt. How ever this relies on creating a XmlDocument as magnifico mentioned. This can be achieved by:

XmlDocument doc = new XmlDocument();
doc.Load( filename );
doc.InsertBefore( doc.CreateDocumentType( "doc_type_name", null, DtdFilePath, null ), 
    doc.DocumentElement );


/// <summary>
/// Class to test a document against DTD
/// </summary>
/// <param name="doc">XML The document to validate</param>
private static bool ValidateDoc( XmlDocument doc )
{
    bool isXmlValid = true;
    StringBuilder xmlValMsg = new StringBuilder();

    StringWriter sw = new StringWriter();
    doc.Save( sw );
    doc.Save( TestFilename );

    XmlReaderSettings settings = new XmlReaderSettings();
    settings.ProhibitDtd = false;
    settings.ValidationType = ValidationType.DTD;
    settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings;
    settings.ValidationEventHandler += new ValidationEventHandler( delegate( object sender, ValidationEventArgs args )
    {
        isXmlValid = false;
        xmlValMsg.AppendLine( args.Message );
    } );

    XmlReader validator = XmlReader.Create( new StringReader( sw.ToString() ), settings );

    while( validator.Read() )
    {
    }
    validator.Close();

    string message = xmlValMsg.ToString();
    return isXmlValid;
}
bstoney
  • 6,594
  • 5
  • 44
  • 51
  • I'd vote this up 20 times if I could. I've gotten SOOO close but this did it. Thanks! – CindyH Nov 09 '11 at 22:17
  • Really useful answer. For those who read this, the most recent version of .NET framework prefers settings.DtdProcessing = DtdProcessing.Parse instead of settings.ProhibidDtd = false. – artragis Jul 15 '14 at 08:43
  • So, the solution is still that we have to add the DOCTYPE string at the beginning? Is there a way for the code to point to an external location not specified in the DOCTYPE string? – Harvey Lin May 04 '17 at 20:21
  • That "ProhibitDtd" is a nasty bomb that only MS could have invented. A more honest naming for this setting would have been LetsGetRidAllAllStandardComplianceSoAsToMakeYourLifeMiserable, which length and expressiveness is on par with .NET's style. – Johan Boulé Sep 14 '18 at 23:14
1

Could you create an Xml.XmlDocument with the DTD you want, then append the XML file data to the in-memory Xml.XmlDocument, then validate that?

Jim Counts
  • 12,535
  • 9
  • 45
  • 63
-1
private static bool _isValid = true;
static void Main(string[] args)
{
    using (MemoryStream ms = new MemoryStream())
    {
        using (FileStream file = new FileStream("C:\\MyFolder\\Product.dtd", FileMode.Open, FileAccess.Read))
        {
            byte[] bytes = new byte[file.Length];
            file.Read(bytes, 0, (int) file.Length);
            ms.Write(bytes, 0, (int) file.Length);
        }
        using (FileStream file = new FileStream("C:\\MyFolder\\Product.xml", FileMode.Open, FileAccess.Read))
        {
            byte[] bytes = new byte[file.Length];
            file.Read(bytes, 0, (int) file.Length);
            ms.Write(bytes, 0, (int) file.Length);
        }
        ms.Position = 0;

        var settings = new XmlReaderSettings();
        settings.DtdProcessing = DtdProcessing.Parse;
        settings.ValidationType = ValidationType.DTD;
        settings.ValidationEventHandler += new ValidationEventHandler(OnValidationEvent);
        var reader = XmlReader.Create(ms, settings);

        // Parse the file.  
        while (reader.Read()) ;
    }
    // Check whether the document is valid or invalid.
    if (_isValid)
        Console.WriteLine("Document is valid");
    else
        Console.WriteLine("Document is invalid");
}

private static void OnValidationEvent(object obj, ValidationEventArgs args)
{
    _isValid = false;
    Console.WriteLine("Validation event\n" + args.Message);
}
Matt
  • 1
  • 2
    Your answer should contain an explanation of your code and a description how it solves the problem. – AbcAeffchen Nov 03 '14 at 20:22
  • I could not find a way for xml to be validated against an external DTD document. In my case, I'm receiving XML from a tcp/ip socket and I want to validate this against a DTD file. The above example shows how you can combine a DTD and some XML together in the same stream before using the the XmlReader object to do the DTD validation. – Matt Nov 06 '14 at 20:42