tags:

views:

83

answers:

2

I’m creating a small application (a phonebook), actually I already created it using ms access as a database, but now, I’m learning XML and planning to use it as a database for this app (just for fun and educational purposes).

Here’s the diagram in my access database.

alt text

And I created two XML files with the same structure as for the two access tables.

ContactList Table

<?xml version="1.0" standalone="yes"?>
<ContactList>
  <xs:schema id="ContactList" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="ContactList" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="Contact">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="ContactID" type="xs:int" minOccurs="0" />
                <xs:element name="Name" type="xs:string" minOccurs="0" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:complexType>
    </xs:element>
  </xs:schema>
  <Contact>
    <ContactID>1</ContactID>
    <Name>Peter</Name>
  </Contact>
  <Contact>
    <ContactID>2</ContactID>
    <Name>John</Name>
  </Contact>
</ContactList>

ContactNumbers Table

<?xml version="1.0" standalone="yes"?>
<ContactNumbers>
  <xs:schema id="ContactNumbers" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="ContactNumbers" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="Numbers">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="ContactID" type="xs:int" minOccurs="0" />
                <xs:element name="Mobile" type="xs:string" minOccurs="0" />
                <xs:element name="Office" type="xs:string" minOccurs="0" />
                <xs:element name="Home" type="xs:string" minOccurs="0" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:complexType>
    </xs:element>
  </xs:schema>
  <Numbers>
    <ContactID>1</ContactID>
    <Mobile>+63-9277-392607</Mobile>
    <Office>02-890-2345</Office>
    <Home>0</Home>
  </Numbers>
  <Numbers>
    <ContactID>2</ContactID>
    <Mobile>+62-9277-392607</Mobile>
    <Office>02-890-2345</Office>
    <Home>1</Home>
  </Numbers>
</ContactNumbers>

This is how my simple app should look like:

alt text

In my original app, I used INNER JOIN statement to retrieve the contact numbers of a particular contact. But now, I have no idea how to do it since I’m using 2 XML files as the tables (corresponding to the two ms access tables). Is it still possible to query and link these two XML files and achieved the same functionality as my first application (using access) version does?

For now, this is what I only have:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TestXML
{
    public partial class Form1 : Form
    {
        OpenFileDialog openFileDialog1 = new OpenFileDialog();
        DataSet ds = new DataSet();
        DataView dv = new DataView();

        public Form1()
        {
            InitializeComponent();
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            try
            {
                openFileDialog1.Filter = "XML Document (*.xml)|*.xml";
                openFileDialog1.FileName = "";
                openFileDialog1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    txtDirectory.Text = openFileDialog1.FileName;                    
                    btnLoad.Enabled = true;
                }
            }
            catch (Exception x)
            {
                btnLoad.Enabled = false;
                MessageBox.Show("Something went wrong! \n" + x.Message, "Ooops!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        private void btnLoad_Click(object sender, EventArgs e)
        {
            dgContactList.DataSource = LoadXML();
        }

        private DataView LoadXML()
        {
            try
            {
                ds.Clear();
                ds.ReadXml(txtDirectory.Text, XmlReadMode.ReadSchema);
                dv = ds.Tables[0].DefaultView;
                lblStatus.Text = "XML is loaded successfully";
            }
            catch (Exception x)
            {
                MessageBox.Show("Something went wrong! \n" + x.Message, "Ooops!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                lblStatus.Text = "";
            }
            return dv;
        }
    }
}
A: 

I personally don't like to work with DataView, DataTable and so on. I would created classes that correspond to your XML data. Eg. Contact and Numbers. Then I would read in the data using XDocument with XML LINQ syntax. You create a collection of contacts that you are going to set on the first GridView, and after clicking you just read the selected object from the collection and set the data on the second GridView.

No need for inner joins, everything is defined in classes and clearly better readable. Just an opinion.

EDIT:

More Infos:

Create classes that represent your data, e.g. Contact, Numbers

Read about XDocument at MSDN.

Example:

XDocument contactDoc = XDocument.Load(m_helpTopicFile);
var contacts = from xmlTopic in contactDoc.Descendants("Contact")
select new Contact
                     {
                         Id = int.Parse(xmlTopic.Element("ContactID").Value, CultureInfo.InvariantCulture),
                         Name = xmlTopic.Element("name").Value,

                     };

Then set this as the DataSource by using contacts.ToList()

testalino
just a beginner...I have no idea about what you said..hehe
yonan2236
I edited my answer, hope this helps
testalino
+1  A: 

Here is my solution(MainList is your 1st XML and DetailedList is the second.)

using System;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Linq;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog OpenFD = new OpenFileDialog();
            OpenFD.InitialDirectory = Application.StartupPath;
            OpenFD.FileName = "";
            OpenFD.ShowDialog();
            if (OpenFD.FileName == "")
                return;
            textBox1.Text = OpenFD.FileName;
            ReadXMLFile(OpenFD.FileName);
        }
        private void ReadXMLFile(String strFileName)
        {
            var X = XDocument.Load(strFileName).Descendants("Contact").Select(N => new
        {
            ID = N.Element("ContactID").Value,
            Name=N.Element("Name").Value 
        });
        foreach (var XX in X)
        {
            dataGridView1.Rows.Add(XX.ID, XX.Name);
        }
    }


    private void dataGridView1_RowHeaderMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
    {
        String St = dataGridView1.SelectedRows[0].Cells[0].Value.ToString();
        var Data = XDocument.Load(Application.StartupPath + "\\DetailedList.xml").Descendants("Numbers")
                         .Where(X=>X.Element("ContactID").Value ==St)
                         .Select(N => new
                          {
                              Mobile = N.Element("Mobile").Value,
                              Office = N.Element("Office").Value,
                              Home = N.Element("Home").Value
                          });
        dataGridView2.Rows.Clear();
        foreach (var X in Data)
        {
            dataGridView2.Rows.Add(X.Mobile,X.Office,X.Home);
        }
    }
}
}

Output

Result

Add the necessary property to both the gridViews

I've created the columns at the design time.

And Instead of foreach we can wse LAMBDA Expression Hope you will understand.... Please let me know if you have any isses.

Enjoy!!!!!

Pramodh
Wow! hehe, thank you very much sir for your answer :). I'm very glad someone has posted an answer, and it works. Though it's not that easy to understand, especially for just like me, beginner. But I will do more reading and play around with your code, all I want is to have an example in order for me to study it and serve as a basis in building a more advance application and coding, little by little. Thanks again :)
yonan2236
I barely understand `LAMDA Expression`
yonan2236