Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

XML reading question (Urgent)

Posted on 2006-04-06
18
Medium Priority
?
312 Views
Last Modified: 2013-11-19
<DataType>
   <PetOwned>
      <PetType value = Dog>
       <Age value = 1>
       <Fleas value = None>
       <Tank Value = none>
       <WaterType value = none>
   </PetOwned>
</DataType>
<DataType>
   <PetOwned>
      <PetType value = Fish>
       <Age value = unknown>
       <Fleas value = None>
      <Tank Value = 10gal>
      <WaterType value = Fresh>
   </PetOwned>
</DataType>

Ok the above XML is an example.

What I am trying to do is loop through the PetTypes (I have this working) and get the type of pet.

Based on the type of pet I am only going to need to pull certain nodes out and place them into a text box. (this I am stuck on)

example for Pet Type Dog.  I only need The age. For fish I only need the 10gal

How do I pull the nodes under that specific PetType node?  Right now I have it pulling the first one in the xml even if the PetType does not match. Does anyone have any code examples.

         // Loop through all messages,saving any messages that are found in an array.
         XmlNodeList nodeListType = xmlDoc.SelectNodes("/DataType/PetOwned/PetType");
         foreach (XmlNode xmlNodeType in nodeListType)
         {
           string sNameType = xmlNodeType.Attributes["value"].InnerText;

            //pull where the typenode is Dog
            if (sNameType =="Dog")
            {
                //only pull the needed nodes for example Age, Fleas
            }
            else if (sNameType == "Fish"
            {
               //only pull the needed nodes for example Tank, Watertype
             }

0
Comment
Question by:NewMom2Brandon
  • 9
  • 7
  • 2
18 Comments
 
LVL 18

Expert Comment

by:Ravi Singh
ID: 16394468
Hi, the example XML given wasn't well formed, if you had the corrected version below:

<?xml version="1.0"?>
<root>
      <DataType>
               <PetOwned>
                        <PetType value="Dog">
                               <Age value="1"/>
                               <Fleas value="None"/>
                               <Tank value="none"/>
                               <WaterType value="none"/>
                  </PetType>
               </PetOwned>
      </DataType>
      <DataType>
               <PetOwned>
                        <PetType value="Fish">
                               <Age value="unknown"/>
                               <Fleas value="None"/>
                              <Tank value="10gal"/>
                              <WaterType value="Fresh"/>
                  </PetType>
               </PetOwned>
      </DataType>
</root>


then to access them values you'd have something like:

      // Loop through all messages,saving any messages that are found in an array.
      XmlNodeList nodeListType = xmlDoc.DocumentElement.SelectNodes("DataType/PetOwned/PetType");
                  
      foreach (XmlNode xmlNodeType in nodeListType)
      {
            string sNameType = xmlNodeType.Attributes["value"].InnerText;

            //pull where the typenode is Dog
            if (sNameType == "Dog")
            {
                  //only pull the needed nodes for example Age, Fleas
                  this.textBox1.Text = xmlNodeType.SelectSingleNode("Age").Attributes["value"].InnerText;
            }
            else if (sNameType == "Fish")
            {
                  //only pull the needed nodes for example Tank, Watertype
                  this.textBox2.Text = xmlNodeType.SelectSingleNode("Tank").Attributes["value"].InnerText;
            }
      }

Hope this helps!
0
 
LVL 18

Expert Comment

by:Ravi Singh
ID: 16394552
Notice that to select the PetType nodes I used an xpath relative to the root element (DocumentElement):

XmlNodeList nodeListType = xmlDoc.DocumentElement.SelectNodes("DataType/PetOwned/PetType");

Your original way would have been:

XmlNodeList nodeListType = xmlDoc.SelectNodes("root/DataType/PetOwned/PetType");

0
 
LVL 96

Accepted Solution

by:
Bob Learned earned 2000 total points
ID: 16394808
If you have control over the XML format, I would suggest this format:

<?xml version="1.0"?>
<Data>
     <DataType>
             <PetOwned type="Dog" age="1" fleas="None" tank="none" water="none"/>
     </DataType>
     <DataType>
             <PetOwned type ="Fish" age ="unknown" fleas value="None" tank="10gal" water="Fresh"/>
     </DataType>
</Data>

You could do XPath expressions like this:

  //PetOwned[@type='Dog']

Bob
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 2

Author Comment

by:NewMom2Brandon
ID: 16394881
I am still getting the first PetType value instead of what I really want.

here is my actual code for what I am working on

      private void LoadTCPXML()
      {
         // Load XML document
         XmlDocument xmlDoc = new XmlDocument();
         xmlDoc.Load(sConfigFile);

         // Loop through all errorlog messages,saving any messages that are found in an array.
         XmlNodeList nodeListType = xmlDoc.DocumentElement.SelectNodes("/Config/PI/Connection/Type");
         foreach (XmlNode xmlNodeType in nodeListType)
         {
           string sNameType = xmlNodeType.Attributes["value"].InnerText;

            //pull where the typenode is TCP/IP
            if (sNameType =="TCP/IP")
            {
               string sType = xmlNodeType.SelectSingleNode("/Config/PI/Connection/Type").Attributes["value"].InnerText;
               string sConnect = xmlNodeType.SelectSingleNode("/Config/PI/Connection/To").Attributes["value"].InnerText;
               string sIPAddress = xmlNodeType.SelectSingleNode("/Config/PI/Connection/IPAddress").Attributes["value"].InnerText;
               string sIPPort = xmlNodeType.SelectSingleNode("/Config/PI/Connection/IPPort").Attributes["value"].InnerText;

               listviewConfiguration.Items.Add(sType);
               listviewConfiguration.Items[0].SubItems.Add(sConnect);
               listviewConfiguration.Items[0].SubItems.Add(sIPAddress + ", " + sIPPort);
            }
         }
      }

So the code is looping through and finding the correct Type value "TCP/IP" however when I try to have it placed into the listview. It populates it with the first set only "Serial"

My actual XML File is like this

<PI>
   <Connection>
      <Type value="Serial" />
      <To value="Computer1" />
      <IPAddress value="10.10.10.11" />
      <IPPort value="9999" />
   </Connection>
 </PressInterface>
<PressInterface>
   <Connection>
      <Type value="TCP/IP" />
      <To value="Computer2" />
      <IPAddress value="10.10.10.10" />
      <IPPort value="9998" />
   </Connection>
 </PI>
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 16394930
Use this expression, and see if it helps:

XmlNodeList nodeListType = xmlDoc.DocumentElement.SelectNodes("//Type");

Bob
0
 
LVL 2

Author Comment

by:NewMom2Brandon
ID: 16394957
Nope still get the first one. "Serial"
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 16394993
I used this XML file:

<?xml version="1.0" ?>
<Data>
<DataType>
   <PetOwned>
      <PetType value = "Dog"/>
       <Age value = "1"/>
       <Fleas value = "None"/>
       <Tank Value = "none"/>
       <WaterType value = "none"/>
   </PetOwned>
</DataType>
<DataType>
   <PetOwned>
      <PetType value = "Fish" />
       <Age value = "unknown" />
       <Fleas value = "None" />
      <Tank Value = "10gal" />
      <WaterType value = "Fresh" />
   </PetOwned>
</DataType>
</Data>

And, this test code:

    XmlDocument doc = new XmlDocument();
    doc.Load(@"c:\temp\test.xml");

    foreach (XmlNode node in doc.SelectNodes("//PetType"))
    {
      Debug.WriteLine(node.Name );
    }

It wrote two entries in the Output window.

Bob
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 16395011
Do you have control over the format of that XML file?

Bob
0
 
LVL 2

Author Comment

by:NewMom2Brandon
ID: 16395169
I do but there are so many nodes that if I place them all in one line it would be really long.
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 16395243
Are you saying that you have more than 1 set of entries under the <Connection> node.  It looks like you only have 1 per connection.  Have you over simplified the XML file that you are showing us?

It would like this this to me:

<PI>
 <PressInterface>
   <Connection type="Serial" to="Computer1" ip="10.10.10.11" port="9999" />
 </PressInterface>
<PressInterface>
   <Connection type="TCP/IP" to="Computer2" ip="10.10.10.10" port="9998" />
 </PressInterface>
</PI>

That seems like significantly less text then having a node + attribute for each value.

Bob
0
 
LVL 2

Author Comment

by:NewMom2Brandon
ID: 16395318
here is the complete XML file (no modifications from me minus small value detail)

<?xml version="1.0"?>
<Config>
<PI>
   <Identifier value="1" />
   <DllName value="XXXX.dll" />
   <Interface value="T2" />
   <Connection>
      <Identifier value="1" />
      <Type value="Serial" />
      <To value="computer1" />
      <IPAddress value="localhost" />
      <IPPort value="6980" />
      <Parameters>
             <SerialPort value="XXXX1" />
       <BaudRate value="19200" />
       <Databits value="8" />
       <Parity value="None" />
       <Stopbits value="1" />
       <Timeout value="0" />
       <CTS value="0" />
       <DTR value="0" />
       <Device value="1" />
       <Node value="255" />
       <BusType value="PCI" />
      </Parameters>
   </Connection>
 </PI>
 <PI>
   <Identifier value="1" />
   <DllName value="XXXX.dll" />
   <Interface value="T1" />
   <Connection>
      <Identifier value="1" />
      <Type value="TCP/IP" />
      <To value="computer2" />
      <IPAddress value="10.10.10.10" />
      <IPPort value="6999" />
      <Parameters>
             <SerialPort value="XXXX1" />
       <BaudRate value="19200" />
       <Databits value="8" />
       <Parity value="None" />
       <Stopbits value="1" />
       <Timeout value="0" />
       <CTS value="0" />
       <DTR value="0" />
       <Device value="1" />
       <Node value="255" />
       <BusType value="PCI" />
      </Parameters>
    </Connection>
 </PI>
</Config>

So for a "Serial" I need everything under the parameters plus the Identifier, Type  and To under the connection
For "TCP/IP" I need the Identifier, Type  and To, IPAddress and IPPort under the connection
0
 
LVL 2

Author Comment

by:NewMom2Brandon
ID: 16395357
The SerialPort Value block is actually over. Sorry didn't line up right

<?xml version="1.0"?>
<Config>
<PI>
   <Identifier value="1" />
   <DllName value="XXXX.dll" />
   <Interface value="T2" />
   <Connection>
      <Identifier value="1" />
      <Type value="Serial" />
      <To value="computer1" />
      <IPAddress value="localhost" />
      <IPPort value="6980" />
      <Parameters>
          <SerialPort value="XXXX1" />
          <BaudRate value="19200" />
          <Databits value="8" />
          <Parity value="None" />
          <Stopbits value="1" />
          <Timeout value="0" />
          <CTS value="0" />
          <DTR value="0" />
          <Device value="1" />
          <Node value="255" />
          <BusType value="PCI" />
      </Parameters>
   </Connection>
 </PI>
 <PI>
   <Identifier value="1" />
   <DllName value="XXXX.dll" />
   <Interface value="T1" />
   <Connection>
      <Identifier value="1" />
      <Type value="TCP/IP" />
      <To value="computer2" />
      <IPAddress value="10.10.10.10" />
      <IPPort value="6999" />
      <Parameters>
          <SerialPort value="XXXX1" />
          <BaudRate value="19200" />
          <Databits value="8" />
          <Parity value="None" />
          <Stopbits value="1" />
          <Timeout value="0" />
          <CTS value="0" />
          <DTR value="0" />
          <Device value="1" />
          <Node value="255" />
          <BusType value="PCI" />
      </Parameters>
    </Connection>
 </PI>
</Config>
0
 
LVL 2

Author Comment

by:NewMom2Brandon
ID: 16395368
The to value can actually be to computer1 again
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 16395393
The inherent problem with XML files are they are significantly over-bloated with information.  There is an optimization step to include only as much information as necessary to get the job done.  It shouldn't matter how each entry is, but the amount of characters that need to be stored.  It comes in handy to think about things like this when you have to send XML over the wire, such as with a web service.

<?xml version="1.0"?>
<Config>
<PI id="1" dll="XXXX.dll" interface="T2">
   <Connection id="1" type="Serial" to="computer1" ip="localhost" port="6980">
      <Parameters>
            <SerialPort name="XXXX1" baud="19200" data="8" parity="None" stop="1" timeout="0" cts="0" dtr="0" device="1" node="255" bus="PCI" />
      </Parameters>
   </Connection>
 </PI>
</Config>

In my opinion, this XML structure is easier to read (since it is more compact), and you can still do XPath expressions using the attribute syntax that I showed you above.

Bob
0
 
LVL 2

Author Comment

by:NewMom2Brandon
ID: 16395647
OK so I switched the XML to look like this
<Config>
<PI Identifier ="1" DllName =" xxxx.dll" Interface=" T2">
   <Connection Identifier ="1" Type="Serial" To="computer1" IPAddress ="localhost" IPPort ="6980">
      <Parameters>
            < SerialPort ="COM1" BaudRate ="19200" Databits ="8" Parity ="None" Stopbits ="1" Timeout ="0" CTS ="0" DTR ="0" Device ="1" Node ="255" BusType ="PCI" />
      </Parameters>
   </Connection>
 </PI >
<PI Identifier ="1" DllName =" xxxx.dll" Interface=" T2">
   <Connection Identifier ="1" Type="TCP/IP" To="computer1" IPAddress ="10.10.10.10" IPPort ="6989">
      <Parameters>
            <SerialPort ="COM1" BaudRate ="19200" Databits ="8" Parity ="None" Stopbits ="1" Timeout ="0" CTS ="0" DTR ="0" Device ="1" Node ="255" BusType ="PCI" />
      </Parameters>
   </Connection>
 </PI >
<Config>

and I get this error (listed below) on this line
         foreach (XmlNode xmlNodeType in xmlDoc.SelectNodes("//Connection[@Type='TCP/IP']"))

An unhandled exception of type 'System.Xml.XmlException' occurred in system.xml.dll
Additional information: System error.
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 16395822
1) It is important that whenever you change XML text, that you test it with something like Internet Explorer.  

2) Here is the XML file that I came up with:

<?xml version="1.0" ?>
<Config>
<PI Identifier="1" DllName="xxxx.dll" Interface="T2">
   <Connection Identifier="1" Type="Serial" To="computer1" IPAddress="localhost" IPPort="6980">
      <Parameters>
            <Serial port="COM1" baud="19200" data="8" parity="None" stop="1" timeout="0" cts="0" dtr="0" device="1" node="255" bus="PCI" />
      </Parameters>
   </Connection>
 </PI>
<PI Identifier="1" DllName="xxxx.dll" Interface="T2">
   <Connection identifier="1" type="TCP/IP" to="computer1" ip="10.10.10.10" port="6989">
      <Parameters>
            <Serial port="COM1" baud="19200" data="8" parity="None" stop="1" timeout="0" cts="0" dtr="0" device="1" node="255" bus="PCI" />
      </Parameters>
   </Connection>
 </PI>
</Config>

3) You will notice some things:  
   a) No spaces in elements names
   b) Serial port=, and not SerialPort=
 
4) Keep the white space to a minimum.

5) Use short, lowercase names for attributes.

6) Use try...catch blocks to get real exceptions.

7) foreach (XmlNode xmlNodeType in xmlDoc.SelectNodes("//Connection[@type='TCP/IP']")) will now select one node.

Bob
0
 
LVL 2

Author Comment

by:NewMom2Brandon
ID: 16400447
I am sorry to ask one more quick question.

How do I change this line then                
string sType = xmlNodeType.SelectSingleNode("//Connection[@Type]").Attributes["value"].InnerText;

      foreach (XmlNode xmlNodeType in xmlDoc.SelectNodes("//Connection[@Type='TCP/IP']"))
         {
            string sType = xmlNodeType.SelectSingleNode("//Connection[@Type]").Attributes["value"].InnerText;
            string sConnect = xmlNodeType.SelectSingleNode("//Connection[@To]").Attributes["value"].InnerText;
            string sIPAddress = xmlNodeType.SelectSingleNode("//Connection[@IPAddress]").Attributes["value"].InnerText;
            string sIPPort = xmlNodeType.SelectSingleNode("//Connection[@IPPort]").Attributes["value"].InnerText;

               listviewConfiguration.Items.Add(sType);
               listviewConfiguration.Items[0].SubItems.Add(sConnect);
               listviewConfiguration.Items[0].SubItems.Add(sIPAddress + ", " + sIPPort);
          }
               

0
 
LVL 2

Author Comment

by:NewMom2Brandon
ID: 16400628
Got it thank you Bob!!
0

Featured Post

Important Lessons on Recovering from Petya

In their most recent webinar, Skyport Systems explores ways to isolate and protect critical databases to keep the core of your company safe from harm.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Entity Framework is a powerful tool to help you interact with the DataBase but still doesn't help much when we have a Stored Procedure that returns more than one resultset. The solution takes some of out-of-the-box thinking; read on!
SASS allows you to treat your CSS code in a more OOP way. Let's have a look on how you can structure your code in order for it to be easily maintained and reused.
Viewers will learn one way to get user input in Java. Introduce the Scanner object: Declare the variable that stores the user input: An example prompting the user for input: Methods you need to invoke in order to properly get  user input:
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …
Suggested Courses

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question