XML
Børre Stenseth
Moduler>XML>XML Inspeksjon

Innholdet i en XML-fil

Hva
screen
Inspisere en enkel XML-fil

I System.Xml finner vi batteriet for å handtere XML-filer. I dette enkle eksempelet leser vi inn en XML-fil med en liste av personbeskrivelser. Vi parser fila, bygger opp et DOM-tre, legger alle personene ut i en listebox og lar brukeren inspisere en person av gangen.

Programmet er svært lite fleksibelt, både fila vi kan inspisere og delvis strukturen vi forventer er hardkodet i programmet. Det er en forholdsvis enkel sak å endre dette ved å innføre en dialogboks for å åpne filer og en litt mer fleksible kode for å presentere XML-elementer.

Vi baserer oss på en enkel XML-fil som ser slik ut:

<?xml version="1.0" encoding="ISO-8859-1"?>
<alle>
	<person>
		<e-navn>Olsen</e-navn>
		<f-navn>Ole</f-navn>
		<adr>Halden</adr>
	</person>
	<person>
		<e-navn>Hansen</e-navn>
		<f-navn>Hans</f-navn>
		<adr>Moss</adr>
	</person>
	<!-- and more -->
</alle>

Versjon 1

Versjon en er basert på en egen klasse, nodeLink, som kopler det XML-elementet vi vil vise fram i lista med en presentasjons metode, ToString. Klassen er slik:

// This class represent a DOM-element in the listBox
public class nodeLink : Object
{
    XmlElement XMLElt;
    public nodeLink(XmlElement elt)
    { XMLElt = elt; }
     
    public override string ToString()
    {return XMLElt.FirstChild.InnerText;}
     
    public XmlElement getElement
    { get { return XMLElt; } }
}

Objekter av typen nodeLink representerer en personnode i listeboksen. Vi ser at en array av objekter av denne typen er en slags indextabell som hjelper oss å representere en person i listeboksen: ToString produserer den teksten som går inn i listeboksen, mens XMLElt er det elementet i XML-treet teksten representerer.

Selve formen er slik:

public partial class Form1 : Form
{
    XmlDocument doc = null;
    public Form1()
    {
        InitializeComponent();
    }
    
    // load the file and fill the listbox
    private void buttonLoad_Click(object sender, EventArgs e)
    {
        textBox1.Text = "";            
        // load the file and establish DOM
        doc = new XmlDocument();
        try
        {
            // assume file in startup catalog
            doc.Load(Path.Combine(Application.StartupPath, 
                                  "xmlfil.xml"));
            XmlNodeList list = doc.GetElementsByTagName("person");
            for (int ix = 0; ix < list.Count; ix++)
                listBoxItems.Items.Add(
                    new nodeLink((XmlElement)list.Item(ix)));
            listBoxItems.Refresh();
        }
        catch (Exception ex)
        {
            // errormessage in the textbox
            textBox1.Text = ex.Message;
        }
    }
    // pick up click and display items content
    private void listBoxItems_MouseClick(object sender, MouseEventArgs e)
    {
        // we have clicked on a listitem, which one ?
        nodeLink selected = (nodeLink)listBoxItems.SelectedItem;
        XmlElement p = selected.getElement;
        textBox1.Text = String.Format("{0} {1} fra {2} ",
             p.GetElementsByTagName("f-navn")[0].InnerText,
             p.GetElementsByTagName("e-navn")[0].InnerText,
             p.GetElementsByTagName("adr")[0].InnerText);
    }
}

Løsningen med å bruke tekstfeltet til to ting, presentasjon av data for en person og feilmelding ved feil i XML-fila, er neppe i tråd med god design.

Versjon 2

I denne versjonen kutter vi ut klassen som pakker inn XML-elementet, nodelink. I stedet oppretter vi et bindingSource objekt med XmlElement som datasource, og vi lar listeboksen bruke dette objektet som dataSource og innerText som DisplayMember.

Vi pakkker bare etternavnet inn i listeboksen og finner hele personelement som parentNode når vi skal vise fram informasjonen om en person.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.IO;
namespace testingxml
{        
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        
        // load the file and fill the listbox
        // the bindigsource has datasource XmlElement
        // the list has Displaymember innerText
        private void buttonLoad_Click(object sender, EventArgs e)
        {
            textBox1.Text = "";            
            // load the file and establish DOM
            XmlDocument doc = new XmlDocument();
            try
            {
                // assume file in startup catalog
                doc.Load(Path.Combine(Application.StartupPath,"xmlfil.xml"));
                // we want to put e-navn in the list
                XmlNodeList list = doc.GetElementsByTagName("e-navn");
                for (int ix = 0; ix < list.Count; ix++)
                    bindingSource1.Add(list.Item(ix));
                listBoxItems.Refresh();
            }
            catch (Exception ex)
            {
                // errormessage in the textbox
                textBox1.Text = ex.Message;
            }
        }
          
        // pick up click and display items content
        private void listBoxItems_MouseClick(object sender, MouseEventArgs e)
        {
            // we have clicked on a listitem, which one ?
            XmlElement p_en = (XmlElement)listBoxItems.SelectedItem;
            // get the person element
            XmlElement p = (XmlElement)p_en.ParentNode;
            textBox1.Text = String.Format("{0} {1} fra {2} ",
                p.GetElementsByTagName("f-navn")[0].InnerText,
                p.GetElementsByTagName("e-navn")[0].InnerText,
                p.GetElementsByTagName("adr")[0].InnerText);
            
         }
    }
}
Referanser
Prosjekt versjon 1:
https://svn.hiof.no/svn/psource/Csharpspikes/xmlinspect
Versjon 2:
https://svn.hiof.no/svn/psource/Csharpspikes/xmlinspect2
Vedlikehold
B.Stenseth, revidert januar 2011
(Velkommen) Moduler>XML>XML Inspeksjon (XML utvalg)