XML
XPATH
Børre Stenseth
Moduler>XML>XML utvalg

Utvalg fra XML

Hva
screen
Inspisere en enkel XML-fil

Vi skal gjøre en svært enkel øvelse på en XML-fil. Vi bruker fila med olympiske sprintresultater, slik den er beskrevet i modulen Noen datasett. Dataene ser slik ut: olympiske data

Oppgaven er å fylle en listeboks med registrerte olymiader. Brukeren skal deretter kunne klikke på en olymiade og få opp en liste av 100m-finalister.

Versjon 1

Løsningen er basert på etableringen av et XmlDocument:

String xmlsource =
    "http://www.it.hiof.no/~borres/commondata/olympiade/all_results.xml";
XmlDocument doc=null;

Data lastes og listeboksen med oversikt over olympiader fylles opp:

private void buttonLoad_Click(object sender, EventArgs e)
{
    doc = new XmlDocument();
    listBoxOlymp.Items.Clear();
    try
    {
        doc.Load(xmlsource);
        labelMsg.Text = "Loaded";
        XmlNodeList list = 
            doc.GetElementsByTagName("OlympicGame");
        foreach (XmlElement nod in list)
            listBoxOlymp.Items.Add(new connect(nod));
    }
    catch (Exception ex)
    {
        labelMsg.Text = ex.Message;
    }
}

Her er det valgt å lage en egen klasse, connect, som hjelper oss å kople olymiadens navn til XmlElementet som representerer en olympiade. Denne klassen er slik:

// to connect an XMLElement to a listentry
class connect
{
    XmlElement elt;
    public connect(XmlElement elt)
    {this.elt = elt;}
    public override string ToString()
    {return elt.GetAttribute("place");}
    public XmlElement Elt{get{return elt;}}
}

Når brukeren klikker i olympiadelist blir jobben å finne alle deltagerne på 100m i den olympiaden.

private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    // walking the tree, level by level
    listBoxAthlets.Items.Clear();
    connect cnt = (connect)listBoxOlymp.SelectedItem;
    XmlElement elt = cnt.Elt;
    XmlNodeList list = elt.GetElementsByTagName("event");
    foreach (XmlElement evelt in list)
    {
        if (evelt.GetAttribute("dist") == "100m")
        {
            XmlNodeList atlist = evelt.GetElementsByTagName("athlet");
            foreach (XmlElement at in atlist)
                listBoxAthlets.Items.Add(at.GetElementsByTagName("name")[0].InnerText);
        }
    }
}

Alternativt kan vi bruke XPATH til å finne de aktuelle løperne.

private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    // using xpath
    listBoxAthlets.Items.Clear();
    connect cnt = (connect)listBoxOlymp.SelectedItem;
    XmlElement elt = cnt.Elt;
    XmlNodeList list =elt.SelectNodes("event[@dist='100m']/athlet");
    foreach (XmlElement at in list)
        listBoxAthlets.Items.Add(at.GetElementsByTagName("name")[0].InnerText);
}

Versjon 2

I denne versjonen baserer vi oss på at det kun har vært en olympiade på hvert sted. Det vil si at "place"-attributten entydig identifiserer en olympiade. Med dette utgangspunktet kan vi legge bare olypiade-stedet i lista og så bruke XPATH til å finne 100m-finalistene.

Etableringen av olymiadelista blir slik, uten noe connect-objekt:

private void buttonLoad_Click(object sender, EventArgs e)
{
    doc = new XmlDocument();
    listBoxOlympiade.Items.Clear();
    try
    {
        doc.Load(xmlsource);
        labelMsg.Text = "Loaded";
        XmlNodeList list = 
            doc.SelectNodes("//OlympicGame");
        foreach (XmlElement nod in list)
            listBoxOlympiade.Items.Add(nod.GetAttribute("place"));
    }
    catch (Exception ex)
    {
        labelMsg.Text = ex.Message;
    }
}

Utvalg av 100m-finalister blir slik:

private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    listBox100m.Items.Clear();
    String place=(string)listBoxOlympiade.SelectedItem;
    String myXpath = 
        String.Format(
           "//OlympicGame[@place='{0}']/event[@dist='100m']/athlet/name",
           place
           );
    try
    {
        XmlNodeList list = doc.SelectNodes(myXpath);
        foreach (XmlElement at in list)
            listBox100m.Items.Add(at.InnerText);
    }
    catch (Exception ex)
    {
        labelMsg.Text = ex.Message;
    }
}

versjon 3

Vi snur problemet slik at vi begynner med en liste av sprintere som har deltatt i en av de aktuelle olympiadene, for så å finne ut hvor vedkommende har deltatt.

screen2

Etableringen av personlista blir slik:

private void buttonLoad_Click(object sender, EventArgs e)
{
    listBox1.Items.Clear();
    doc = new XmlDocument();
    try
    {
        doc.Load(xmlsource);
        // fill the listbox with names
        XmlNodeList personer = doc.SelectNodes("//name");
        foreach(XmlNode p in personer)
        {
            String n=p.InnerText;
            if (!listBox1.Items.Contains(n))
                listBox1.Items.Add(n);
        }
        labelMsg.Text = "loaded";
    }
    catch (Exception ex)
    {
        labelMsg.Text = ex.Message;
    }
}

Når vi skal velge fra lista kan vi bruke DOM-programmering:

private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    String n = (string)listBox1.SelectedItem;
    textBoxWhat.Text = n + "\r\n";
    XmlNodeList deltagelse = 
        doc.SelectNodes(String.Format("//athlet[name='{0}']",n));
    foreach (XmlNode d in deltagelse)
    {
        String ovelse = 
            ((XmlElement)d.ParentNode).
            GetAttribute("dist");
        String olymp = 
            ((XmlElement)d.ParentNode.ParentNode).
            GetAttribute("place");
        textBoxWhat.Text += 
            String.Format("deltok på {0} i {1}\r\n",ovelse,olymp);
    }
}

eller vi kan bruke XPATH

private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    String n = (string)listBox1.SelectedItem;
    textBoxWhat.Text = n + "\r\n";
    XmlNodeList deltagelse =
        doc.SelectNodes(String.Format("//athlet[name='{0}']", n));
    foreach (XmlNode d in deltagelse)
    {
        String ovelse = 
            ((XmlElement)d.SelectSingleNode("..")).
            GetAttribute("dist");
        String olymp =
            ((XmlElement)d.SelectSingleNode("../..")).
            GetAttribute("place");
        textBoxWhat.Text +=
            String.Format("deltok på {0} i {1}\r\n", ovelse, olymp);
    }
}
Referanser

Eksemplene

  • Eksempel1:
    https://svn.hiof.no/svn/psource/Csharpspikes/xmlfun1
  • Eksempel2:
    https://svn.hiof.no/svn/psource/Csharpspikes/xmlfun2
  • Eksempel3:
    https://svn.hiof.no/svn/psource/Csharpspikes/xmlfun3

Det samme temaet er behandlet i modulen XPATH og sprint

Vedlikehold

B.Stenseth, januar 2008

(Velkommen) Moduler>XML>XML utvalg (XML Vedlikehold)