views:

271

answers:

3

I have an xml formatted document that looks like this:

    <?xml version="1.0" encoding="windows-1250"?>
< Recipe>
  < Entry name="Stuffed Red Cabbage" ethnicity="Slavic" />
  < Cook_Time Hrs="1" Mins="30" />
  < Ingredients>
              < Cabbage Amount="1" Measurement="head" />
              < Egg Amount="1" Measurement="unit" />
              < Ground_Beef Amount="1" Measurement="lb" />
              < Margarine Amount="1/2" Measurement="cup" />
              < Onion Amount="1" Measurement="unit" />
              < Rice Amount="1" Measurement="cup" />
              < Tomato_Soup Amount="3" Measurement="cans" />
  < /Ingredients>
  < Description>core cabbage and boil until leaves start pulling away. Strip leaves and let cool.
chop onion and place in frying pan with margarine and heat till lightly browned.
put ground beef, rice, onion, egg and salt to taste in bowl and mix.
stuff each leaf with mixture.
put tomato soup and stuffed leaves in pot and cook for about an hour.</Description>
</Recipe>

and I have code that so far looks like this:

OpenFileDialog1.Filter = "RecipeBook files (*.rcp)|*.rcp"
    If OpenFileDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
        Try
            Dim settings As New XmlReaderSettings()
            settings.IgnoreComments = True
            Dim RecipeCard As String = OpenFileDialog1.FileName
                            Dim xmlreader As XmlTextReader
            xmlreader = New XmlTextReader(RecipeCard)
            Do While xmlreader.Read
                'needs to read xml and write appropriate items to database and listview
                xmlreader.MoveToContent()
                If xmlreader.Name.Equals("Entry") Then
                    MessageBox.Show(xmlreader.GetAttribute("name") & " " & xmlreader.GetAttribute("ethnicity"), "test")
                End If
                If xmlreader.Name.Equals("Cook_Time") Then
                    MessageBox.Show(xmlreader.GetAttribute("Hrs") & " hrs " & xmlreader.GetAttribute("Mins") & " mins", "test")
                End If
                If xmlreader.Name.Equals("Ingredients") Then

                End If
            Loop
        Catch
        End Try
    End If

My question has to do with parsing the Ingredients section. I was planning on doing something like this:

Dim IngredientCount As Integer = 0
Dim count As Integer = (something here that gets the count of subelements inside the Ingredients element)
                    For i = 1 To count
                    MessageBox.Show(xmlreader.GetAttribute("Amount") & " " & xmlreader.GetAttribute("Measurement"), "test")
                    Next

I just can't figure out how to get the number of subelements and then how to refer to each one in succession to get the name and then the attributes of that subelement. Any suggestions would be greatly appreciated.

A: 

What I've done for this in the past is call Read() to get each subelement in turn. After each Read(), check that it's a start element. If it's not a start element then you've reached the end of the enclosing Ingredient tag and it's time to read the next one. The sample code in this documentation might be helpful:

http://msdn.microsoft.com/en-us/library/xaxy929c.aspx

XmlReader cannot give you the number of subelements of the current element because it reads one tag at a time. It hasn't read those other elements yet so it doesn't know how many there are. If you want to get more info on the XML tree while you're reading it, use XmlDocument. However, XmlDocument will read the whole file into memory at once before you even start processing it, whereas XmlReader reads the file from start to finish as you process it. XmlReader should be faster and more memory-efficient.

The sample here shows how to iterate over attributes if you don't know ahead of time which attributes an element will have:

http://msdn.microsoft.com/en-us/library/system.xml.xmlreader.movetonextattribute.aspx

Nate C-K
+3  A: 

One of your comments indicates you are using the 3.5 framework. If so then you can take advantage of XML literals to get your solution.

Dim data = XDocument.Load(xmlReader)
Dim count = data.<Ingredients>.Elements().Count()
JaredPar
Thaaaaaank you for eventually using XML literals ... Nobody seems to know or use them ;) +1
Dario
+1  A: 

If you want to use the XmlTextReader then you can solve your problem by using ReadSubtree:

If xmlreader.Name.Equals("Ingredients") Then
    Dim inner As XmlReader
    inner = xmlreader.ReadSubtree()
    inner.Read()
    While inner.Read
        If inner.IsStartElement Then
            MessageBox.Show(inner.GetAttribute("Amount") & " " & inner.GetAttribute("Measurement"), "test")
         End If
    End While
End If

It'd be easier though to not use XmlTextReader and instead use Linq to XML.

Mark Byers
This option worked the best for everything I had in place already. It isn't the most efficient as far as memory goes, but it was the easiest to implement.
MaQleod