XML
XSD
Schema
Validering
Børre Stenseth
Moduler>XML>Validering

Validering av XML

Hva
Validering av XML mot Schema

Vi bruker fila med olympiske sprint resultater som utgangspunkt og bygger en applikasjon som skal demonstrere to ting:

  • bruk av løpernavn som enkel nøkkel for å lokalisere løperens deltagelse i flere olympiader.
  • validering av XML-fil mot Schema-fil

Image1

Råmaterialet er beskevet i modulen Noen datasett, og har denne strukturen


<?xml version="1.0" encoding="ISO-8859-1"?>
<IOC>
  <OlympicGame place="Barcelona" year="1992">
    <event dist="100m">
      <athlet>
        <name>Dennis Mitchell</name>
        <nation>USA</nation>
        <result>10.04</result>
      </athlet>
      ...
    </event>
    ...
  </OlympicGame>
  ...
</IOC>

I sin helhet: all_results.xml

Hvem er hvem

Vi ønsker å lage en liste av deltagere (athlets) der hver deltager er representert kun en gang. Vi baserer oss da på at navnet er god nok identifikasjon. Koden for å etablere lista og finne en deltagers deltagelse blir slik:

// adding name of athlets to listbox
private void buttonAthlets_Click(object sender, EventArgs e)
{
    if (m_Doc == null) { return; }
    XmlNodeList alist = m_Doc.SelectNodes("//name");
    foreach (XmlElement aelt in alist)
    {
        String nText = aelt.InnerText;
        // already there ?
        if (listBoxSelection.Items.IndexOf(nText) == -1)
            listBoxSelection.Items.Add(nText);
    }
}

// selecting an athletname, report all performances
private void listBoxSelection_SelectedIndexChanged(object sender, EventArgs e)
{
    String t = listBoxSelection.SelectedItem.ToString();
    String xpath = String.Format("//athlet[name='{0}']", t);
    XmlNodeList same = m_Doc.SelectNodes(xpath);
    textBox1.Text = "";
    foreach (XmlElement a in same)
    {
        textBox1.Text += String.Format("{0} i {1} - {2}\r\n",
                     ((XmlElement)a.ParentNode).GetAttribute("dist"),
                     ((XmlElement)a.ParentNode.ParentNode).GetAttribute("place"),
                     ((XmlElement)a.ParentNode.ParentNode).GetAttribute("year"));
    }
}

Validering

Vi ønsker å validere fila med resultater. Vi kan gjøre dette på mange måter. Her bruker vi en enkel framgangsmåte:

  1. last opp XML-fila i Visual Studio
  2. fra menyen XML, velg Create Schema
  3. lage denne i prosjektkatalogen
  4. adder schema-fila til prosjektet
  5. sørg for at både xml-fila og schema-fila kopieres til den katalogen applikasjonen kjøres
String XSDFILEPATH = 
	Path.Combine(Application.StartupPath, "all_results.xsd");
String XMLFILEPATH = 
	Path.Combine(Application.StartupPath, "all_results.xml");

Følgende kode etablerer XmlDocumentet, viser det i en webbrowser kontrol og validerer.

private void postInitialize()
{
    try
    {
        String filename=Path.Combine(Application.StartupPath,
                             "all_results.xml");
        webBrowser1.Url = new Uri(XMLFILEPATH);
        m_Doc = new XmlDocument();
        
        // will fail if malformed or not found
        m_Doc.Load(XMLFILEPATH);
        m_Doc.Normalize();
        
        // validate
        XmlReaderSettings settings = new XmlReaderSettings();
        settings.Schemas.Add(null, XSDFILEPATH);
        settings.ValidationType = ValidationType.Schema;
        settings.ValidationEventHandler += 
            new ValidationEventHandler(SchemaValidationEventHandler);
        XmlReader rdr = 
            XmlReader.Create(new StringReader(m_Doc.InnerXml), settings);
        while (rdr.Read()) { }
     }
    catch (Exception ex)
    {
        webBrowser1.DocumentText = 
            String.Format(@"<html><body>
                          <p>Sorry:</p>
                          <p>{0}</p>
                          </body></html>", ex.Message);
        m_Doc = null;
    }
}

Merk metoden SchemaValidationEventHandler som gor oss advarsler ogfeilmeldinger under valideringen.

// pick up validation errors/warnngs
// report in text box
private void SchemaValidationEventHandler(object sender, ValidationEventArgs e)
{
    switch (e.Severity)
    {
        case XmlSeverityType.Error:
            textBox1.Text += String.Format("\r\nError: {0}", e.Message);
            break;
        case XmlSeverityType.Warning:
            textBox1.Text += String.Format("\r\nWarning: {0}", e.Message);
            break;
    }
}

Vi har valgt et enkelt demonstarsjonseksempel, laget schema-fila ukritisk og brukt den uten endringer. I de fleste tilfelle ønsker vi å validere filer som er laget eller importert fra programmer vi ikke har kontroll over. En fornuftig framgangsmåter er trolig å lage en schema-fil basert på et eksempel og deretter editere denne for hånd for å generalisere og eller presisere. Den schema-fila vi får laget i dette eksempelet ser slik ut:

<?xml version="1.0" encoding="iso-8859-1"?>
<xs:schema attributeFormDefault="unqualified" 
           elementFormDefault="qualified" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="IOC">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" name="OlympicGame">
          <xs:complexType>
            <xs:sequence>
              <xs:element maxOccurs="unbounded" name="event">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element maxOccurs="unbounded" name="athlet">
                      <xs:complexType>
                        <xs:sequence>
                          <xs:element name="name" type="xs:string" />
                          <xs:element name="nation" type="xs:string" />
                          <xs:element name="result" type="xs:decimal" />
                        </xs:sequence>
                      </xs:complexType>
                    </xs:element>
                  </xs:sequence>
                  <xs:attribute name="dist" type="xs:string" use="required" />
                </xs:complexType>
              </xs:element>
            </xs:sequence>
            <xs:attribute name="place" type="xs:string" use="required" />
            <xs:attribute name="year" type="xs:unsignedShort" use="required" />
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

For å kunne bearbeide denne må vi sette oss inn hvordan xsd-filer er bygget opp. Vi forfølger ikke dette her, men det er mye å hente både i presisering av lovlige verdirer og i generalisering av hvordan validerbare filer kan bygges opp. Er det f.eks. viktig at elementene name, nation,result kommer i nøyaktig den rekkefølgen ? En modifisert versjon kan se slik ut:

_modified.xsd

Koden i Formen er i sin helhet slik:

_Form1.cs

Enkelt valideringseksempel

Et enkelt eksempel som gjør det lett å eksperimentere med schemaer og validering. Eksempelet er bygget rundt de samme dataene som over, men programmet gjør ikke annet enn å laste en XML-fil og validere den.

screen2

Koden i Formen er i sin helhet slik:

_Form12.cs

Du kan lett bytte ut eller endre innholdet i de to filene: results.xml og schema.xsd, eller du kan ganske enkelt endre adressen i formen.

Referanser
Prosjekt:
https://svn.hiof.no/svn/psource/Csharpspikes/xmlvalidate
Enklet eksempel;
https://svn.hiof.no/svn/psource/Csharpspikes/xmlvalidate2
Vedlikehold
B.Stenseth, revidert januar 2011
(Velkommen) Moduler>XML>Validering (RSS-leser)