質問

I need to parse the XML below using Visual Basic .NET. In the past I found a workaround through XSLT, adapting the XML to my needs, but I seriously want to know how this needs to be done without workarounds. I'll paste the XML first, and then I'll let you know where and why I get stuck:

<browse result="1" first="1" last="16" total="16">
    <th>
        <td label="dimension" hideforuser="false" type="String">fin.trs.line.dim2</td>
        <td label="Outstanding" hideforuser="false" type="Value">fin.trs.line.openbasevaluesigned</td>
        <td label="Factuurbedrag" hideforuser="false" type="Value">fin.trs.line.basevaluesigned</td>
        <td label="Invoice Number" hideforuser="false" type="String">fin.trs.line.invnumber</td>
        <td label="" hideforuser="false" type="String">fin.trs.head.code</td>
        <td label="Pay date" hideforuser="false" type="Date">fin.trs.line.matchdate</td>
        <td label="Vervaldatum" hideforuser="false" type="Date">fin.trs.line.datedue</td>
        <td label="Datum" hideforuser="false" type="Date">fin.trs.head.date</td>
        <td label="boektype" hideforuser="false" type="String">fin.trs.head.status</td>
        <td label="paystatus" hideforuser="false" type="String">fin.trs.line.availableforpayruns</td>
    </th>
    <tr>
        <td field="fin.trs.line.dim2" hideforuser="false" type="String">01603</td>
        <td field="fin.trs.line.openbasevaluesigned" hideforuser="false" type="Value">-792.00</td>
        <td field="fin.trs.line.basevaluesigned" hideforuser="false" type="Value">-800.00</td>
        <td field="fin.trs.line.invnumber" hideforuser="false" type="String">789</td>
        <td field="fin.trs.head.code" hideforuser="false" type="String">INK</td>
        <td field="fin.trs.line.matchdate" hideforuser="false" type="Date" name="14/03/2012">20120314</td>
        <td field="fin.trs.line.datedue" hideforuser="false" type="Date" name="13/04/2012">20120413</td>
        <td field="fin.trs.head.date" hideforuser="false" type="Date" name="14/03/2012">20120314</td>
        <td field="fin.trs.head.status" hideforuser="false" type="String" name="Definitief">final</td>
        <td field="fin.trs.line.availableforpayruns" hideforuser="false" type="String" name="Ja">true</td>
        <key>
            <office>DACMI3-1</office>
            <code>INK</code>
            <number>201200019</number>
            <line>1</line>
        </key>
    </tr>
<tr>
        <td field="fin.trs.line.dim2" hideforuser="false" type="String">11123</td>
        <td field="fin.trs.line.openbasevaluesigned" hideforuser="false" type="Value">300.00</td>
        <td field="fin.trs.line.basevaluesigned" hideforuser="false" type="Value">300.00</td>
        <td field="fin.trs.line.invnumber" hideforuser="false" type="String">11112</td>
        <td field="fin.trs.head.code" hideforuser="false" type="String">INK</td>
        <td field="fin.trs.line.matchdate" hideforuser="false" type="Date"/>
        <td field="fin.trs.line.datedue" hideforuser="false" type="Date" name="13/04/2012">20120413</td>
        <td field="fin.trs.head.date" hideforuser="false" type="Date" name="14/03/2012">20120314</td>
        <td field="fin.trs.head.status" hideforuser="false" type="String" name="Definitief">final</td>
        <td field="fin.trs.line.availableforpayruns" hideforuser="false" type="String" name="Ja">true</td>
        <key>
            <office>DACMI3-1</office>
            <code>INK</code>
            <number>201200021</number>
            <line>1</line>
        </key>
    </tr>
    </browse>

To keep it readable for everyone I have truncated the XML. There are about 15 more <tr> sections in the actual XML. The XML is a response I'm getting from a webservice.

I've tried every piece of code I could find on the web, but I got stuck on each and everyone of them. That's why I'm not going to show you what I tried already, please take my word for it that I've spent two years on it.

What is my problem:

1. As you can see the XML starts out with a <th> section (which is not of importance to me, that is simply the webservice telling me what I asked for). So that part needs to be disregarded. But it is on the same 'level' as the <tr> blocks which I DO need, so how do I skip the <th> one and start at the <tr> ones? As in a for each tr thing.

2. I need every value and name within the <tr> blocks, but the names are not specified by tags, but by attributes. If you look at the <tr> blocks; instead of

<dim2>01603</dim2>

it is put down as

<td field="fin.trs.line.dim2" hideforuser="false" type="String">01603</td>

for every <tr> block I need the fin.trs.line.dim2 part (so the field name) and the actual value. So how do I do that?

3. Each <tr> block has a childnode called <key>, which (as it kind of tells) holds key values for each block. How do I retrieve those values, and make sure I know they belong to the <tr> block it is in?

I've been reading tutorials and websites forever, but I simply don't seem to be able to understand this part.

Just to make sure, this is for Visual Basic NET (2010, if you need to know).

P.S.: The XML is in a string.

役に立ちましたか?

解決

You can use LINQ2XML to take the tr elements only and then extract the attribute and the value from the th element using the XDocument.Descendants and XAttribute method. To find the key elements use the Descendants method again on the tr element. The solution could look like this:

dim xmlSource = File.ReadAllText("d:\temp\source.xml")
' read the XML (HTML) code
dim xml = XDocument.Parse(xmlSource)
' find all tr elements
dim trs = xml.Root.Descendants("tr").ToList()
' iterate over each one of them
for Each tr in trs
    ' find all td elements for each tr
    dim tds = tr.Descendants("td")
    ' iterate over each one of them
    for each td as XElement in tds
        ' find the attribute with the name field
        dim attr as XAttribute = td.Attribute("field")
        ' if found
        if not (attr.Value = nothing) then
            ' take the attribute name and the element value (td value)
            Console.WriteLine(String.Format("{0} - {1}", attr.Value, td.Value))
        end if
    next
    ' find element key that belongs to this tr
    dim keys = tr.Descendants("key")
    for each key as XElement in keys
        dim keyNodes = key.Elements()
        for each keyNode as XElement in keyNodes
            Console.WriteLine(String.Format("{0} - {1}", keyNode.Name, keyNode.Value))
        next
    next
next

The output is (just a part of it):

...
fin.trs.head.date - 20120314
fin.trs.head.status - final
fin.trs.line.availableforpayruns - true
office - DACMI3-1
code - INK
number - 201200021
line - 1
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top