Loop each Items in c# using XElement

257 views Asked by At

I am facing some difficulty in swapping the id attribute in the list of Items in a C# XDocument. The id is a reference.

Input:

<Items>
    <Item base="book_bookref1_ref1">
        <Name>Test1</Name>
        <Ref>bookref1</Ref>
    </Item>
    <Item base="book_bookref1_ref2">
        <Name>Test2</Name>
        <Ref>bookref1</Ref>
    </Item>
    <Item base="book_bookref2_ref1">
        <Name>Test3</Name>
        <Ref>bookref2</Ref>
    </Item>
    <Item base="book_bookref2_ref2">
        <Name>Test4</Name>
        <Ref>bookref2</Ref>
    </Item>
</Items>

Expected Output:

<Items>
    <Item base="book_bookref1_ref1" id="book_bookref1_ref2">
        <Name>Test1</Name>
        <Ref>bookref1</Ref>
    </Item>
    <Item base="book_bookref1_ref2" id="book_bookref1_ref1">
        <Name>Test2</Name>
        <Ref>bookref1</Ref>
    </Item>
    <Item base="book_bookref2_ref1" id="book_bookref2_ref2">
        <Name>Test3</Name>
        <Ref>bookref2</Ref>
    </Item>
    <Item base="book_bookref2_ref2" id="bookref2_ref1">
        <Name>Test4</Name>
        <Ref>bookref2</Ref>
    </Item>
</Items>

There is a tag <Ref> where one part of value ex:bookref1 is a reference for Base attribute book_bookref1_ref1 for the 1st and 2nd Item.

I need to write the 2nd 'id' to the 1st Item and write the 1st id to the 2nd Item in the loop. Similarly for the 3rd and 4th Item. There can be many but it's like a combination (1 & 2, 3 & 4, 5 & 6, etc).

The problem here is there can be multiple Items and there is no relation in the Item to map the Id attribute.

The code I'm using is loading XMLDocument into XDocument getting the Items in LINQ.

Var doc = XDocument.Load(xml) 
var ItemsList 
foreach(var itm in ItemsList)
{
    // I'm stuck here. How do we get the id attribute value based on Ref tag?
}

Please let me know your suggestions.

1

There are 1 answers

0
Robert Synoradzki On

Nothing in XML is impossible with a little LINQ (and MoreLinq, in this example):

var xdoc = XDocument.Parse(input);
foreach(var pair in xdoc.XPathSelectElements("Items/Item").Batch(2).ToArray())
{
    pair[0].SetAttributeValue(XName.Get("id"), pair[1].Attribute(XName.Get("base")).Value);
    pair[1].SetAttributeValue(XName.Get("id"), pair[0].Attribute(XName.Get("base")).Value);
}

This enumerates not each Item, not each Item pair (two elements in a batch). You only need to tweak this to decide what to do if an odd element remains at the end of the loop.

MoreLinq is for .Batch() extension method, but if you need, you can easily write it yourself.