Karl
Karl

Reputation: 956

Cant validate simple (or complex) XML with DTD using c# and vs2017

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.

Upvotes: 0

Views: 478

Answers (1)

Karl
Karl

Reputation: 956

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()
            };

Upvotes: 1

Related Questions