Search code examples
xmlvb.netlinqlinq-to-xmlxelement

Adding multiple xElements at once using LINQ to XML


I have below custom class:

Public Class Frame

#Region " Enumerations "

    Public Enum FrameResult
        Success
        Failed
    End Enum

#End Region

#Region " Private Members "

    Private _timeStamp As Date
    Private _content As String
    Private _result As String

#End Region

#Region " Constructors "

    Sub New(ByVal timeStamp As Date, ByVal content As String, ByVal result As FrameResult)
        Me._timeStamp = timeStamp
        Me._content = content
        Me._result = result.ToString
    End Sub

#End Region

#Region " Properties "

    Public Property TimeStamp() As Date
        Get
            Return Me._timeStamp
        End Get

        Set(ByVal value As Date)
            Me._timeStamp = value
        End Set
    End Property

    Public Property Content() As String
        Get
            Return Me._content
        End Get

        Set(ByVal value As String)
            Me._content = value
        End Set
    End Property


    Public Property Result() As FrameResult
        Get
            Return DirectCast([Enum].Parse(GetType(FrameResult), Me._result), FrameResult)
        End Get

        Set(ByVal value As FrameResult)
            Me._result = value.ToString
        End Set
    End Property

#End Region


End Class

And I am trying to add multiple xElements at once to a XML document depending on if xml file exists or not:

Public Sub Add(ByVal frameData() as Frame) {

     if FileExists(xmlFile) then
        ' XML File exists

        xElem = XElement.Load(xmlFile)
        xElem.Add(frameData) --> not working

        ' Persist changes to file. Save to Disk
        xElem.Save(xmlFile)

     else
         ' File does not exist

        xDoc = New XDocument(New XDeclaration("1.0", "UTF-8", Nothing))
        xDoc.Root.Add(frameData)       

        sw = New StringWriter()
        xWrite = XmlWriter.Create(sw)

        xDoc.Save(xWrite)
        xWrite.Close()

        ' Persist changes to file. Save to Disk
        xDoc.Save(xmlFile)

     End If

But it does not work. I have tried to do:

       Dim _frame as Frame

       xDoc = New XDocument(New XDeclaration("1.0", "UTF-8", Nothing), _
        new XElement("Frames", _
        from _frame in frameData <--- not working, needs implements IQueryable
         select new XElement("TimeStamp", _frame.TimeStamp), _
            new XElement("Content", _frame.Content), _
            new XElement("Result", _frame.Result)))

but it does not work as frameData does not implements IQueryable and it seems so difficult... is there any other easy way?

My xml file looks like:

<?xml version="1.0" encoding="UTF-8"?>
<frames>
    <frame>
        <timestamp>20/10/2016 07:30:05 AM</timestamp>
        <content>bla bla bla </content>
        <status>OK</status>
    </frame>
    <frame>
        <timestamp>20/10/2016 15:10:12 PM</timestamp>
        <content>bla bla bla </content>
        <status>FAIL</status>
    </frame>

    ... NEXT FRAMES ...

</frames>

Solution

  • I would use XML Literals, which allow you to embed expressions to build up your XML from your objects. It seems more natural to me than all those nested New XElement. e.g.

    Dim frameData = {
        New Frame(Date.Now, "A", Frame.FrameResult.Success),
        New Frame(Date.Now, "B", Frame.FrameResult.Success),
        New Frame(Date.Now, "C", Frame.FrameResult.Failed),
        New Frame(Date.Now, "D", Frame.FrameResult.Success),
        New Frame(Date.Now, "E", Frame.FrameResult.Success),
        New Frame(Date.Now, "F", Frame.FrameResult.Success)
    }
    
    Dim xml As XDocument = <?xml version="1.0" encoding="UTF-8"?><frames></frames>
    
    Dim frames As IEnumerable(Of XElement) =
        From f In frameData
        Select <frame>
                   <timestamp><%= f.TimeStamp %></timestamp>
                   <content><%= f.Content %></content>
                   <status><%= If(f.Result = Frame.FrameResult.Success, "OK", "FAIL") %></status>
               </frame>
    
    xml.Root.Add(frames)
    

    However, your comment about "not working, needs implements IQueryable" makes me wonder if you are missing a reference/import to something... or if I am missing something.