tags:

views:

75

answers:

2

Hi, I'm having trouble groking something in Linq - maybe someone can give me some tips.

I have XML that I need to transform to new XML. The problem with this is that it is I need several iterations of transformation to get it right.

The source would look something like this:

    <Meals>
      <ketchup/>
      <steak/>
      <mustard/>
      <thigh/>
      <fillet/>
      <penne/>
      <drumstick/>
      <steak/>
      <ketchup/>
      <fillet/>
      <fillet/>
      <macaroni/>
      <drumstick/>
      <thigh/>
      <ketchup/>
      <thigh/>
      <fillet/>
    </Meals>

What I'd like this to end up being is:

    <Meals>
      <Meal>
        <ketchup/>
        <steak/>
        <mustard/>
        <thigh/>
      </Meal>
      <Meal>
        <fillet/>
        <penne/>
        <drumstick/>
      </Meal >
      <Meal>
        <steak/>
        <ketchup/>
      </Meal>
      <Meal>
        <fillet/>
      </Meal>
      <Meal>
        <fillet/>
        <macaroni/>
        <drumstick/>
      </Meal>
      <Meal>
        <thigh/>
        <ketchup/>
      </Meal>
      <Meal>
        <thigh/>
        <fillet/>
      </Meal>
    </Meals>

The logic here is that:

  • <steak> and <fillet> are beef meats - anything that occurs before or after them that is not a beef meat part of the meal so long as it's not already part of another meal. If beef meat occurs after a beef meat, a new meal is created at the element of the new beef meat.
  • <thigh> and <drumstick> are chicken meats - anything that occurs before or after them that is not a chicken meat is part of the meal so long as it's not already part of another meal. If chicken meat occurs after a chicken meat, a new meal is created at the element of the new chicken meat.
  • <macaroni> and <penne> are pastas anything that occurs before or after them that is not a pasta is part of the meal so long as it's not already part of another meal. If pasta occurs after a pasta, a new meal is created at the element of the new pasta.
  • <ketchup> and <mustard> are condiments - they can be part of any meal.

I've started with ElementsAfterSelf and ElementsBeforeSelf and TakeWhile, but am running into walls with my understanding of how to perform the above. I'm using VB.NET and Linq, but can read C#.

Any thoughts or pointers?

A: 

You might find LINQPad useful. I'd give your problem a go, but I'm not clear on the combination logic you specified, as it doesn't match up to the example as I understand it (e.g., why isn't mustard in every meal?)

fatcat1111
Thanks. I am using LinqPad - great tool. Mustard isn't in every meal because it only occurs once and is therefore part of the first meal (next meal, in the example above, would be based on when beef switches to a new beef) based on it's location.
Otaku
+3  A: 

Got a good answer from another forum and here's the final:

    Dim meals As XElement = <Meals>
                                <ketchup/>
                                <steak/>
                                <mustard/>
                                <thigh/>
                                <fillet/>
                                <macaroni/>
                                <drumstick/>
                                <thigh/>
                                <ketchup/>
                                <thigh/>
                                <fillet/>
                            </Meals>
    Dim newMeals As XElement = <Meals/>
    Dim meal As XElement = <Meal/>
    Dim hasBeef As Boolean
    Dim hasChicken As Boolean
    For Each m In meals.Descendants()
        Select Case m.Name
            Case Is = "steak", "fillet"
                If hasBeef Then
                    newMeals.Add(meal) 
                    meal = <Meal/> 
                    hasChicken = False
                Else
                    hasBeef = True
                End If
                meal.Add(m)
            Case Is = "drumstick", "thigh"
                If hasChicken Then
                    newMeals.Add(meal)
                    meal = <Meal/>
                    hasBeef = False
                Else
                    hasChicken = True
                End If
                meal.Add(m)
            Case Else
                meal.Add(m)
        End Select
    Next
    newMeals.Add(meal)
Otaku