Ask a questionAsk a question
 

AnswerLinq to XML Help

  • Tuesday, November 03, 2009 6:06 PMTuppers360 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code

    Hi I have the following xml file that I am wanting to use:

    <?xml version="1.0" encoding="utf-8"?>
    
    <Roles>
    
        <Role name="Admin">
    
            <user>user1</user>
    
            <user>user2</user>
    
        </Role>
    
        <Role name="User">
    
            <user>user1</user>
    
            <user>user2</user>
    
            <user>user3</user>
    
        </Role>
    
        <Role name="Guest">
    
            <user>user4</user>
    
            <user>user5</user>
    
        </Role>
    
        <Role name="Power User">
    
            <user>user3</user>
    
        </Role>
    
    </Roles>

    I have the following class with this:

    Public Class Role
    
            Public RoleName As String
    
            Public AssignedUsers As New StringCollection()
    
    End Class
    

    I am using the following code to try and fill the object/class created with the data from the xml file:  

    Dim doc As XDocument = XDocument.Load(fileName)
    
    
    
                        Dim query = From xElem In doc.Descendants("Role") Select New With { _
    
                                    .RoleName = xElem.Attribute("name").Value, _
    
                                    .AssignedUsers = xElem.Element("user").Value}
    
    
    
                        _Roles = query

    _Roles is declared with the following:

    Private _Roles As List(Of Role)
    

    The query works to an extent that it selects all the roles and JUST one user but will not allow itself to be placed into the object. I have tried a Directcast the the object but that does not work either!

    Can anyone see where I am going wrong in placing the query in the store I am using for the roles within my app I am trying but at this moement failing miserably to create!??

    Thanks!

    Tuppers

Answers

  • Tuesday, November 03, 2009 6:27 PMDavid M MortonMVP, ModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    For starters, you're creating an anonymous type.  Note you haven't specified the type after "New" in your select statement.  Change it to this:

    Dim query = From xElem In doc.Descendants("Role") Select New Role With { _
                .RoleName = xElem.Attribute("name").Value, _
                .AssignedUsers = xElem.Element("user").Value}

    Next, you need to check the type of the AssignedUsers property.  It's currently StringCollection.  Change it to a List(Of String).  It should now look like this:

    Public Class Role
        Public RoleName As String
        Public AssignedUsers As List(Of String)
    End Class

    Next, we're going to change what we're getting from the query again.  This query modifies the one above, and is the final revision:

    Dim query = From xElem In doc.Descendants("Role") Select New Role With { _
                .RoleName = xElem.Attribute("name").Value, _
                .AssignedUsers = xElem.Elements("user").Select(Function(x) x.Value).ToList()}

    Now, LINQ queries return an IEnumerable(Of T), not a List(Of T), so you have two options here.  Either change the type of _Roles to an IEnumerable(Of Role), or use the .ToList() method off of query to convert the IEnumerable(Of T) to a List(Of T):

    _Roles = query.ToList();

    Make those changes, and it should work fine. 
    Coding Light - Illuminated Ideas and Algorithms in Software
    Coding Light WikiLinkedInForumsBrowser
    • Marked As Answer byTuppers360 Wednesday, November 04, 2009 6:44 PM
    •  
  • Tuesday, November 03, 2009 6:49 PMMartin Honnen Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     AnswerHas Code
    I wouldn't use a StringCollection in .NET 3.5 code. Why don't you use a List<string> e.g.

    Public Class Role
    
        Private _roleName As String
    
        Public Property RoleName() As String
            Get
                Return _roleName
            End Get
            Set(ByVal value As String)
                _roleName = value
            End Set
        End Property
    
        Private _assignedUsers As List(Of String)
    
        Public Property AssignedUsers() As List(Of String)
            Get
                Return _assignedUsers
            End Get
            Set(ByVal value As List(Of String))
                _assignedUsers = value
            End Set
        End Property
    
    End Class
    
    


            Dim doc As XDocument = XDocument.Load(FileName)
            Dim query As IEnumerable(Of Role) = _
            From role In doc.Root.Elements("Role") _
            Select New Role With { _
            .RoleName = CType(role.Attribute("name"), String), _
            .AssignedUsers = role.Elements("user").Select(Function(u) CType(u, String)).ToList() _
            }
    
            _Roles = query.ToList()
    
    

    MVP XML My blog
    • Marked As Answer byTuppers360 Wednesday, November 04, 2009 6:44 PM
    •  

All Replies

  • Tuesday, November 03, 2009 6:27 PMDavid M MortonMVP, ModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    For starters, you're creating an anonymous type.  Note you haven't specified the type after "New" in your select statement.  Change it to this:

    Dim query = From xElem In doc.Descendants("Role") Select New Role With { _
                .RoleName = xElem.Attribute("name").Value, _
                .AssignedUsers = xElem.Element("user").Value}

    Next, you need to check the type of the AssignedUsers property.  It's currently StringCollection.  Change it to a List(Of String).  It should now look like this:

    Public Class Role
        Public RoleName As String
        Public AssignedUsers As List(Of String)
    End Class

    Next, we're going to change what we're getting from the query again.  This query modifies the one above, and is the final revision:

    Dim query = From xElem In doc.Descendants("Role") Select New Role With { _
                .RoleName = xElem.Attribute("name").Value, _
                .AssignedUsers = xElem.Elements("user").Select(Function(x) x.Value).ToList()}

    Now, LINQ queries return an IEnumerable(Of T), not a List(Of T), so you have two options here.  Either change the type of _Roles to an IEnumerable(Of Role), or use the .ToList() method off of query to convert the IEnumerable(Of T) to a List(Of T):

    _Roles = query.ToList();

    Make those changes, and it should work fine. 
    Coding Light - Illuminated Ideas and Algorithms in Software
    Coding Light WikiLinkedInForumsBrowser
    • Marked As Answer byTuppers360 Wednesday, November 04, 2009 6:44 PM
    •  
  • Tuesday, November 03, 2009 6:49 PMMartin Honnen Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     AnswerHas Code
    I wouldn't use a StringCollection in .NET 3.5 code. Why don't you use a List<string> e.g.

    Public Class Role
    
        Private _roleName As String
    
        Public Property RoleName() As String
            Get
                Return _roleName
            End Get
            Set(ByVal value As String)
                _roleName = value
            End Set
        End Property
    
        Private _assignedUsers As List(Of String)
    
        Public Property AssignedUsers() As List(Of String)
            Get
                Return _assignedUsers
            End Get
            Set(ByVal value As List(Of String))
                _assignedUsers = value
            End Set
        End Property
    
    End Class
    
    


            Dim doc As XDocument = XDocument.Load(FileName)
            Dim query As IEnumerable(Of Role) = _
            From role In doc.Root.Elements("Role") _
            Select New Role With { _
            .RoleName = CType(role.Attribute("name"), String), _
            .AssignedUsers = role.Elements("user").Select(Function(u) CType(u, String)).ToList() _
            }
    
            _Roles = query.ToList()
    
    

    MVP XML My blog
    • Marked As Answer byTuppers360 Wednesday, November 04, 2009 6:44 PM
    •  
  • Tuesday, November 03, 2009 6:59 PMTuppers360 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Super thanks for that!! I do have a few questions on what just happened! but i have no time at the mo to really digest I will repost more than likely tomorrow!

    again thankyou! I am still learning! sorry!

    Tuppers 
  • Wednesday, November 04, 2009 7:22 AMTuppers360 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi thanks for that yesterday I have a question about this part:

    .AssignedUsers = role.Elements("user").Select(Function(u) CType(u, String)).ToList()

    the select statement used here. I get that this selects the list of users within the role element. I have not seen this before could you please explain or point me in the direction of a good book for linq for this as well as in general and/or some online articles using this?

    thanks again!
  • Wednesday, November 04, 2009 11:06 AMMartin Honnen Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    See the VB documentation on lamba expressions . With LINQ you have, for some queries, the choice between the query syntax and the method syntax. So
    role.Elements("user").Select(Function(u) CType(u, String))
    is the same as
    From user In role.Elements("user") Select CType(u, String)
    MVP XML My blog
  • Wednesday, November 04, 2009 2:58 PMTuppers360 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    Thanks your help is much appreciatted.

    I am now having a problem with the following code as I have changed from the stringcollection to the List(Of String):

    Public Overrides Function GetAllRoles() As String()
                Try
                    Dim Results As String() = New String(CurrentStore.Roles.Count) {}
                    For i As Integer = 0 To i < Results.Length
                        Results(i) = CurrentStore.Roles(i).RoleName
                    Next
                    Return Results
                Catch ex As Exception
                    Throw
                End Try
            End Function
    
    i think I should return an arry of results but I am not sure about changing the logic to get there.

    Could you possibly help please?

    regards

    Tuppers and again thanks! Sorry if i should of created a new post!
  • Wednesday, November 04, 2009 3:16 PMTuppers360 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    I have tried something like:

     

    Public Overrides Function GetAllRoles() As String()
                Try
                    Dim Results As New List(Of String)
                    Dim Role As List(Of Role) = CurrentStore.Roles
                    If Role IsNot Nothing Then
                        For Each r In Role
                             NOT SURE WHAT TO PUT HERE!!!
                        Next
    
                    Else
                        Throw New ProviderException("There are no roles to diplay!")
                    End If
                    Return Results.ToArray()
                Catch ex As Exception
                    Throw
                End Try
            End Function

    As you can see I am not sure what to place in the for loop!

     

     

  • Wednesday, November 04, 2009 5:07 PMMartin Honnen Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    What is CurrentStore.Roles exactly? A List(Of Role)? If you want an array of role names then you can simply do
    Return CurrentStore.Roles.Select(Function(r) r.RoleName).ToArray()
    or if you prefer query syntax then e.g.
    Return (From role In CurrentStore.Roles Select role.RoleName).ToArray()

    MVP XML My blog
  • Wednesday, November 04, 2009 6:13 PMTuppers360 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    what can I say! thank you and thank you some more I should be able to move on quite a bit from here I think!! I do have some questions about handling multiple updates on an xml file but I will post that in he XML forum!

    and thank you!

    do you recommend any books for vb or linq? its nice sometimes to get away from the computer screen!

    Cheers

    Tuppers