0

I've been working on an issue trying to validate an XML document with its associated DTD file. Initially I tried converting the example from the (Micorsoft Article) and then read through the post in another Stack-Overflow article (here). In both cases (valid and invalid XML documents) the simple xml file fails to validate and I can't work out why...

My test application is a Windows Forms project with a single form that has a couple of buttons on it, and the following code behind it...

bool isValid = true;
    StringBuilder xml = new StringBuilder();
    StringBuilder messages = new StringBuilder();
    string nl = Environment.NewLine;

    public FormMain()
    {
        InitializeComponent();
    }

    private void ValidateProductXMLButton_Click(object sender, EventArgs e)
    {
        ValidateXML("ProductWithDTD.xml");
        DisplayMessage();
    }

    private void ValidateItemXMLButton_Click(object sender, EventArgs e)
    {
        ValidateXML("ItemWithDTD.xml");
        DisplayMessage();
    }

    private void DisplayMessage()
    {
        MessageBox.Show("XML is " + (isValid ? "" : "NOT ") + "valid" + nl + nl + "Message:" + nl + messages.ToString() + nl + nl + "XML" + nl + xml.ToString());

        isValid = true;
        messages = new StringBuilder();
        xml = new StringBuilder();
    }

    protected void ValidateXML(string xmlFileName)
    {
        try
        {
            XmlReaderSettings xmlSettings = new XmlReaderSettings()
            {   
                DtdProcessing = DtdProcessing.Parse,
                ValidationType = ValidationType.DTD
            };
            xmlSettings.ValidationEventHandler += new ValidationEventHandler(ValidationCallback);

            XmlReader reader = XmlReader.Create(AppDomain.CurrentDomain.BaseDirectory + xmlFileName, xmlSettings);
            while (reader.Read())
            {
                // nothing to do, just validating the xml packet
                xml.AppendLine(reader.ReadOuterXml());
            }
            reader.Close();
        }
        catch (Exception ex)
        {
            messages.AppendLine("ERROR : " + ex.Message);
            isValid = false;
        }
    }

    private void ValidationCallback(object sender, ValidationEventArgs e)
    {
        isValid = false;
        messages.AppendLine(e.Message);
    }

In addition to the code above, the content of my 2 XML files (one valid and one not) and my DTD file are shown below...

ProductWithDTD.xml

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE Product SYSTEM "Product.dtd">
<Product ProductID="123">
    <ProductName>Rugby jersey</ProductName>
</Product>

ItemWithDTD.xml

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE Product SYSTEM "Product.dtd">
<Item ItemID="123">
    <ItemName>Rugby jersey</ItemName>
</Item>

and finally, Product.dtd...

<!ELEMENT Product (ProductName)>
<!ATTLIST Product ProductID CDATA #REQUIRED>
<!ELEMENT ProductName (#PCDATA)>

Even when processing the ProductWithDTD.xml file, I get validation errors stating the Product and ProductName elements are not declared. I'd expect this in the ItemWithDTD.xml file, but not the ProductWithDTD.xml file.

Does anyone have any ideas why this is failing? This is all in preparation for validating cXML EDI packets (which is also not working) and they're much larger documents to validate.

Thanks.

2
  • ValidationCallback is an event that is executed regardless of validation errors. Your isValid=false; is a false assumption. Set a breakpoint and check the properties Commented Feb 21, 2019 at 17:06
  • Thanks, but this doesn't appear to be correct. Once I added the XmlResolver to my XmlReaderSettings declaration, the XML validated successfully (when it was meant to) even with the 'isValid = false' left in place. Commented Mar 18, 2019 at 10:09

1 Answer 1

1

It turns out that there's an issue with the XmlReader actually locating the DTD file to validate against, even if its a local file.

Changing the definition of the XmlReaderSettings to include a default XmlResolver fixed my issue.

            XmlReaderSettings xmlSettings = new XmlReaderSettings()
            {   
                DtdProcessing = DtdProcessing.Parse,
                ValidationType = ValidationType.DTD,
                XmlResolver = new XmlUrlResolver()
            };
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.