Avatar billede jpi Mester
19. juni 2023 - 10:12 Der er 2 kommentarer

Rækkefølge på XML-data

Hej

Jeg har følgende (forsimplede) XML som jeg skal indlæse:

<xmltest>
    <type1>
        <tekst>ABC</tekst>
    </type1>
    <type2>
        <tekst>DEF</tekst>
    </type2>
    <type1>
        <tekst>GHI</tekst>
    </type1>
    <type2>
        <tekst>JKL</tekst>
    </type2>
    <type3>
        <tekst>MNO</tekst>
    </type3>
</xmltest>


Der er lavet følgende klasser:

public class xmltest
    public property type1 as list(of type1)
    public property type2 as list(of type2)
    public property type3 as list(of type3)
end class

public class type1
    public property tekst as string
end class

public class type2
    public property tekst as string
end class

public class type3
    public property tekst as string
end class

Og jeg benytter denne kode til aty indlæse:

Public Sub Indlaes
    Dim reader As New System.Xml.XmlTextReader("filename.txt")
    Dim subreader As System.Xml.XmlReader
    Dim xmlSer As System.Xml.Serialization.XmlSerializer
    Dim result = New cmltest
   
    Do While (reader.Read())
    Select Case reader.NodeType
        Case System.Xml.XmlNodeType.Element
            subreader = reader.ReadSubtree()
            xmlSer = New System.Xml.Serialization.XmlSerializer(result.GetType)
            result = xmlSer.Deserialize(subreader)
            subreader.Close()
    End Select
    Loop
    reader.Close()
End Sub

Rækkefølgen af dataene er vigtig.
Her ender jeg med 3 lister med data inde i en xmltest, men jeg kan ikke genskabe rækkefølgen af dataene.
Jeg tænker at bruge dictionary i stedet og med en entydig id på tværs af de 3 lister/dictionaries, men hvordan får jeg den til at gøre det under indlæsningen?

Der skal helst ikke ændres i den generelle indlæsningsmetode, da en masse andet data og kode allerede benytter dette. Det er kun denne del af xml-filen der driller.
Avatar billede arne_v Ekspert
19. juni 2023 - 20:28 #1
Det er svært at vide præcis hvad der vil virke i din sammenhæng.

Men her er en ide.

Original:


Imports System
Imports System.Collections.Generic
Imports System.Xml
Imports System.Xml.Serialization

Namespace E
    Public Class type1
        Public Property tekst() As String
    End Class
    Public Class type2
        Public Property tekst() As String
    End Class
    Public Class type3
        Public Property tekst() As String
    End Class
    Public Class xmltest
        <XmlElement> _
        Public Property type1() As List(Of type1)
        <XmlElement> _
        Public Property type2() As List(Of type2)
        <XmlElement> _
        Public Property type3() As List(Of type3)
    End Class
    Public Class Program
        Public Shared Sub Dump(o As xmltest)
            Console.WriteLine("type1:")
            For Each t1 As type1 In o.type1
                Console.WriteLine("  {0}", t1.tekst)
            Next
            Console.WriteLine("type2:")
            For Each t2 As type2 In o.type2
                Console.WriteLine("  {0}", t2.tekst)
            Next
            Console.WriteLine("type3:")
            For Each t3 As type3 In o.type3
                Console.WriteLine("  {0}", t3.tekst)
            Next
        End Sub
        Public Shared Sub Main(args As String())
            Dim ser As New XmlSerializer(GetType(xmltest))
            Dim rdr As XmlReader = New XmlTextReader("/Work/test.xml")
            While rdr.Read()
                Select Case rdr.NodeType
                    Case XmlNodeType.Element
                        Dim subrdr As XmlReader = rdr.ReadSubtree()
                        Dim o As xmltest = DirectCast(ser.Deserialize(subrdr), xmltest)
                        Dump(o)
                        subrdr.Close()
                        Exit Select
                    Case Else
                        ' ignore
                        Exit Select
                End Select
            End While
            rdr.Close()
            Console.ReadKey()
        End Sub
    End Class
End Namespace


output:

type1:
  ABC
  GHI
type2:
  DEF
  JKL
type3:
  MNO

Det er meget som forventet, men duer ikke for dig.

Min ide er at bruge en enkelt liste og en basis klasse:


Imports System
Imports System.Collections.Generic
Imports System.Xml
Imports System.Xml.Serialization

Namespace E
    Public Class typex
    End Class
    Public Class type1
        Inherits typex
        Public Property tekst() As String
    End Class
    Public Class type2
        Inherits typex
        Public Property tekst() As String
    End Class
    Public Class type3
        Inherits typex
        Public Property tekst() As String
    End Class
    Public Class xmltest
        <XmlElement(Type := GetType(type1)), XmlElement(Type := GetType(type2)), XmlElement(Type := GetType(type3))> _
        Public Property typex() As List(Of typex)
    End Class
    Public Class Program
        Public Shared Sub Dump(o As xmltest)
            For Each tx As typex In o.typex
                Select Case tx.[GetType]().Name
                    Case "type1"
                        Dim t1 As type1 = DirectCast(tx, type1)
                        Console.WriteLine("Type1 : {0}", t1.tekst)
                        Exit Select
                    Case "type2"
                        Dim t2 As type2 = DirectCast(tx, type2)
                        Console.WriteLine("Type2 : {0}", t2.tekst)
                        Exit Select
                    Case "type3"
                        Dim t3 As type3 = DirectCast(tx, type3)
                        Console.WriteLine("Type3 : {0}", t3.tekst)
                        Exit Select
                End Select
            Next
        End Sub
        Public Shared Sub Main(args As String())
            Dim ser As New XmlSerializer(GetType(xmltest), New Type() {GetType(type1), GetType(type2), GetType(type3)})
            Dim rdr As XmlReader = New XmlTextReader("/Work/test.xml")
            While rdr.Read()
                Select Case rdr.NodeType
                    Case XmlNodeType.Element
                        Dim subrdr As XmlReader = rdr.ReadSubtree()
                        Dim o As xmltest = DirectCast(ser.Deserialize(subrdr), xmltest)
                        Dump(o)
                        subrdr.Close()
                        Exit Select
                    Case Else
                        ' ignore
                        Exit Select
                End Select
            End While
            rdr.Close()
            Console.ReadKey()
        End Sub
    End Class
End Namespace


output:

Type1 : ABC
Type2 : DEF
Type1 : GHI
Type2 : JKL
Type3 : MNO

Den beholder rækkefølgen.

Men om det fungerer i din kontekst er et andet spørgsmål.
Avatar billede jpi Mester
23. juni 2023 - 18:16 #2
Tak, det kigger jeg nærmere på og retter til :)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester