Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[VB.NET/XML] Expression custom column

Pagina: 1
Acties:

  • Lexus!
  • Registratie: December 2003
  • Niet online
In mijn te gebruiken XML heet het te gebruiken object "ZB". Dat object "ZB" heeft 2 punten, "AAD" en "AAG". Beide punten hebben coördinaten, gescheiden met een pipe "|" teken. Dit XML wordt zo aangeleverd, en hier moet ik het dan ook mee doen.

In de te ontwikkelen software is gekozen voor het importeren van de XML in een dataset. Dat doe ik met onderstaande code:
Visual Basic .NET:
1
2
3
Dim myDS As DataSet
Dim fsReadXml As New System.IO.FileStream(myXMLFile, System.IO.FileMode.Open)
myDS.ReadXml(fsReadXml)


Dit werkt. Het resultaat is een dataset met 4 tabellen: ZB, AAE, AAG en point.

Er zijn automatisch relaties gelegd tussen de objecten en hun punten met coördinaten. Dit gebeurd via verborgen kolommen met id's. De connectie tussen deze tabellen heb ik weergegeven in 2 datagrids, die aan elkaar gekoppeld zijn. De eerste datagrid laat de tabel ZB zien, de tweede datagrid laat de bijhorende coördinaten zien van het punt AAE. Dit doe ik met onderstaande code:
Visual Basic .NET:
1
2
3
4
5
6
7
8
Dim myBS As New BindingSource
myBS.DataSource = myDS
 
DataGridView1.DataSource = myBS
DataGridView1.DataMember = "ZB"
 
DataGridView2.DataSource = myBS
DataGridView2.DataMember = "ZB.ZB_AAE.AAE_point"


Tot zover was het even puzzelen naar de preciese aanroep van de relaties, maar het werkt. Hetzelfde geldt voor het databinden van labels etc, waarbij ik de coördinaten laat zien van een in de datagrid met ZB objecten geselecteerd object. Dit gaat met onderstaande code:
Visual Basic .NET:
1
2
TextBox1.DataBindings.Clear()
TextBox1.DataBindings.Add(New Binding("text", myBS, "ZB.ZB_AAG.AAG_point.pos"))


Wat wil ik nu eigenlijk?
Ik wil in 1 datagrid (of liever in 1 tabel) zowel de kolommen van de tabel ZB hebben, als ook de coördinaten van de punten AAE en AAG. Dit lijkt me goed mogelijk, alleen krijg ik het niet voor elkaar om de juiste expressie toe te voegen aan een custom column. In alle voorbeelden bestaat er een directe link tussen de velden, nu zit er een koppeltabel tussen. Ik heb het geprobeerd met onderstaande opties, maar helaas zonder resultaat. Uiteindelijk ben ik gewoon maar gaan gokken, maar ook dat leverde niets op.
Visual Basic .NET:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Dim Test As DataColumn = myDS.Tables("ZB").Columns.Add("test", GetType(String))
Test.Expression = "ZB.ZB_AAE.AAE_point"
'Test.Expression = "Child(ZB.ZB_AAE).point"
'Test.Expression = "Child(ZB_AAE).point"
'Test.Expression = "Child(point)"
'Test.Expression = "Child(pos)"
'Test.Expression = "ZB_AAE.point"
'Test.Expression = "ZB.ZB_AAE.point.pos"
'Test.Expression = "point"
'Test.Expression = "point.pos"
'Test.Expression = "Parent.ZB_AAE.AAE_point.pos"
'Test.Expression = "Parent(ZB_AAE).AAE_point"
'Test.Expression = "Parent.ZB"
'Test.Expression = "ZB_AAE.AAE_point.pos"
'Test.Expression = "Child.ZB_AAE.point.pos"


Ik kom er niet uit, al heb ik het gevoel dat ik erg dichtbij zit. Mocht je een XML willen gebruiken om te testen, je zou het kleine stukje XML kunnen gebruiken wat hieronder staat vermeld:

XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<!-- File Header -->
<DATA xmlns:nl= "http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="file:EN13508.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gml="http://www.opengis.net/gml">
<ZB>
<AAA>AAA</AAA>
<AAD>1</AAD>
<AAE>
<gml:point srsName="Netherlands-RD" srsDimension="2">
<gml:pos>123|456</gml:pos>
</gml:point>
</AAE>
<AAF>2</AAF>
<AAG>
<gml:point srsName="Netherlands-RD" srsDimension="2">
<gml:pos>234|567</gml:pos>
</gml:point>
</AAG>
</ZB>
<ZB>
<AAA>AAA</AAA>
<AAD>3</AAD>
<AAE>
<gml:point srsName="Netherlands-RD" srsDimension="2">
<gml:pos>345|678</gml:pos>
</gml:point>
</AAE>
<AAF>4</AAF>
<AAG>
<gml:point srsName="Netherlands-RD" srsDimension="2">
<gml:pos>456|789</gml:pos>
</gml:point>
</AAG>
</ZB>
</DATA>

  • Tribits
  • Registratie: Augustus 2011
  • Laatst online: 02:56

Tribits

Onkruid vergaat niet

Ik heb ook nog wat pogingen ondernomen om een werkende DataColumn.Expression te vinden maar kwam er helaas ook weinig verder mee. Als alternatief heb ik een Linq query bedacht die een enkele rij teruggeeft per ZB element waarin ook de waarden van de AAE en AAG point en pos elementen opgenomen zijn. Door die als datasource te gebruiken belanden alle gegevens in dezelfde grid.

Visual Basic .NET:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Imports <xmlns:gml="http://www.opengis.net/gml">
...
        Dim myBS As New BindingSource
        Dim doc As XDocument
        doc = XDocument.Load(myXMLFile)

        Dim coordinates = _
            From c In doc.<DATA>.<ZB> _
            Select New With {
                .AAA = c.<AAA>.Value(),
                .AAD = c.<AAD>.Value(),
                .AAE_srsName = c.<AAE>.<gml:point>.First().Attribute("srsName").Value,
                .AAE_srsDimension = c.<AAE>.<gml:point>.First().Attribute("srsDimension").Value,
                .AAE_pos = c.<AAE>.<gml:point>.First().<gml:pos>.First().Value,
                .AAG_srsName = c.<AAG>.<gml:point>.First().Attribute("srsName").Value,
                .AAG_srsDimension = c.<AAG>.<gml:point>.First().Attribute("srsDimension").Value,
                .AAG_pos = c.<AAG>.<gml:point>.First().<gml:pos>.First().Value
            }

        myBS.DataSource = coordinates.ToList()
        DataGridView1.DataSource = myBS

Master of questionable victories and sheer glorious defeats


  • Lexus!
  • Registratie: December 2003
  • Niet online
Tribits bedankt! Dit werkt inderdaad goed, het inlezen vand de XML gaat zelfs een stuk sneller. Waar ik met mijn originele XML bestand 5 seconden nodig heb in mijn routine (zonder zelfs de coordinaten), heeft jouw code er maar 1 seconde voor nodig. Linq is dus het toverwoord waar ik mezelf in ga verdiepen.

  • Tribits
  • Registratie: Augustus 2011
  • Laatst online: 02:56

Tribits

Onkruid vergaat niet

Ik zat er nog even naar te kijken, ik kreeg het in eerste instantie namelijk niet voor elkaar om het resultaat van de query in de grid te krijgen. Ergens bij het uitzoeken wat er verkeerd ging heb ik die ToList op regel 20 toegevoegd maar achteraf gezien blijkt die overbodig. Maakt de code misschien nog een stukje sneller, vooral als het om grote bestanden gaat.

Master of questionable victories and sheer glorious defeats


  • Lexus!
  • Registratie: December 2003
  • Niet online
Tof dat je er nog even naar gekeken hebt, bedankt! Het scheelt inderdaad wel. Op een XML bestand van 1.146.761 regels scheelt het 142 ms. In de XML zitten 32894 objecten, een redelijk groot bestand dus. Dit is nog een"kaal" bestand, er moeten nog zaken aan worden toegevoegd, dus elke tijdwinst is welkom. Dit zijn de timings, al wisselen die wel wat elke keer:
XDocument.Load -> 880 ms
Linq query -> 0! ms
myBS.DataSource = Leidingen.ToList() -> 411ms
myBS.DataSource = Leidingen -> 269 ms
min en max X/Y zoeken -> 938 ms

De min en max X/Y van de objecten vraag ik nu af met onderstaande code. Zou dat ook nog voor verbetering vatbaar zijn?

Visual Basic .NET:
1
2
3
4
5
6
7
8
Dim maxAAEX = (From l In Leidingen Select l.AAE_pos_X).Max
Dim minAAEX = (From l In Leidingen Select l.AAE_pos_X).Min
Dim maxAAEY = (From l In Leidingen Select l.AAE_pos_Y).Max
Dim minAAEY = (From l In Leidingen Select l.AAE_pos_Y).Min
Dim maxAAGX = (From l In Leidingen Select l.AAG_pos_X).Max
Dim minAAGX = (From l In Leidingen Select l.AAG_pos_X).Min
Dim maxAAGY = (From l In Leidingen Select l.AAG_pos_Y).Max
Dim minAAGY = (From l In Leidingen Select l.AAG_pos_Y).Min

  • Tribits
  • Registratie: Augustus 2011
  • Laatst online: 02:56

Tribits

Onkruid vergaat niet

Die query kost waarschijnlijk 0ms omdat de verzameling pas doorlopen wordt op het moment dat je er gebruik van gaat maken. Dat verschijnsel gaat waarschijnlijk tegen je werken op het moment dat je er meerdere keren doorheen gaat lopen zoals je nu dus doet voor het zoeken van min/max waarden. Ik kan het hier wat lastig testen maar volgens mij moet de volgende query er voor zorgen dat je maar 1 keer door de hele verzameling heenloopt om alle min max waarden te vinden en dus een stuk sneller zijn.

Visual Basic .NET:
1
2
3
4
5
6
7
8
9
        Dim MinMax = Aggregate c In coordinates
        Into maxAAEX = Max(Convert.ToInt32(c.AAE_pos_x)),
             minAAEX = Min(Convert.ToInt32(c.AAE_pos_x)),
             maxAAEY = Max(Convert.ToInt32(c.AAE_pos_y)),
             minAAEY = Min(Convert.ToInt32(c.AAE_pos_y)),
             maxAAGX = Max(Convert.ToInt32(c.AAG_pos_x)),
             minAAGX = Min(Convert.ToInt32(c.AAG_pos_x)),
             maxAAGY = Max(Convert.ToInt32(c.AAG_pos_y)),
             minAAGY = Min(Convert.ToInt32(c.AAG_pos_y))


Die conversie naar Int32 was nodig door de manier waarop ik de x en y uit een pos element haal. Als de coördinaten al van het integer type zijn kan je die nog weg halen.

Master of questionable victories and sheer glorious defeats


  • Lexus!
  • Registratie: December 2003
  • Niet online
Ik denk dat het stukje convert toch de nodige vertraging veroorzaakt in bovenstaand voorbeeld. Jouw voorbeeld (wel even Int32 vervangen door Double) duurde 684 ms. Die code is ongetwijfeld netter dan onderstaande oplossing, maar deze oplossing is dan toch 250 ms sneller:
Visual Basic .NET:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
        Dim xMin As Double = 9999999
        Dim yMin As Double = 9999999
        Dim xMax As Double = 0
        Dim yMax As Double = 0
        For Each test In leidingen
            If test.AAE_pos_X > xMax Then xMax = test.AAE_pos_X
            If test.AAE_pos_Y > yMax Then yMax = test.AAE_pos_Y
            If test.AAG_pos_X > xMax Then xMax = test.AAG_pos_X
            If test.AAG_pos_Y > yMax Then yMax = test.AAG_pos_Y
            If test.AAE_pos_X < xMin Then xMin = test.AAE_pos_X
            If test.AAE_pos_Y < yMin Then yMin = test.AAE_pos_Y
            If test.AAG_pos_X < xMin Then xMin = test.AAG_pos_X
            If test.AAG_pos_Y < yMin Then yMin = test.AAG_pos_Y
        Next


Het lastige van deze oplossingen met Linq is dat ik op dit moment niet verder kan gaan dan de huidige procedure. Ik ben er nog niet achter gekomen hoe ik, zonder de intellisence te verliezen, de variabele leidingen kan doorsturen naar andere classes of functies.
Pagina: 1