m0fo
m0fo

Reputation: 2189

Linq to XML Subquery

I have the following XML:

<Event ID="1"..... >
    <SubEvent update="DATETIME" />
    <SubEvent update="DATETIME" />
    <SubEvent update="DATETIME" />
    <SubEvent update="DATETIME" />
    <SubEvent update="DATETIME" />
    <SubEvent update="DATETIME" />
</Event>
<Event ID="2"..... >
    <SubEvent update="DATETIME" />
    <SubEvent update="DATETIME" />
    <SubEvent update="DATETIME" />
    <SubEvent update="DATETIME" />
    <SubEvent update="DATETIME" />
    <SubEvent update="DATETIME" />
</Event>
<Event ID="3"..... >
    <SubEvent update="DATETIME" />
    <SubEvent update="DATETIME" />
    <SubEvent update="DATETIME" />
    <SubEvent update="DATETIME" />
    <SubEvent update="DATETIME" />
    <SubEvent update="DATETIME" />
</Event>

I want to remove the "Event" elements where ALL update attribute in the SubEvent are lower than the provided DATETIME.

If, for example one DATETIME is higher, the element should NOT be removed.

Upvotes: 1

Views: 728

Answers (3)

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236248

Simply select all those events and remove them from document:

DateTime date = DateTime.Now;
XDocument xdoc = XDocument.Load(path_to_xml);
xdoc.Descendants("Event")
    .Where(e => e.Elements().All(se => (DateTime)se.Attribute("update") < date))
    .Remove();
xdoc.Save(path_to_xml);

Works fine with following xml:

<?xml version="1.0" encoding="utf-8" ?>
<Events>
  <Event ID="1" >
    <SubEvent update="2013-02-05T17:06:23.8962976+03:00" />
    <SubEvent update="2013-03-08T17:06:23.8962976+03:00" />
  </Event>
  <Event ID="2">
    <SubEvent update="2013-01-05T17:06:23.8962976+03:00" />
    <SubEvent update="2013-01-05T17:06:23.8962976+03:00" />
    <SubEvent update="2013-02-05T17:06:23.8962976+03:00" />
  </Event>
  <Event ID="3">
    <SubEvent update="2013-03-05T17:06:23.8962976+03:00" />
    <SubEvent update="2013-04-05T17:06:23.8962976+03:00" />
  </Event>
</Events>

Upvotes: 3

Freddie Fabregas
Freddie Fabregas

Reputation: 1203

Try this:

        var doc = XDocument.Load(@"D:\input.xml");
        var x = new List<XElement>();
        foreach (var xElement in doc.Root.Elements("Event"))
        {
            DateTime maxDt = DateTime.MinValue;

            foreach (var element in xElement.Elements("SubEvent"))
            {
                var attributeValue = element.Attributes("update").FirstOrDefault();

                if (attributeValue == null) continue;

                DateTime dt;
                if (!DateTime.TryParse(attributeValue.Value, out dt)) continue;

                if (maxDt < dt) maxDt = dt;
            }

            xElement.RemoveNodes();
            xElement.Add(new XElement("SubEvent", new XAttribute("update", maxDt.ToString("yyyy-MM-dd HH:mm:ss"))));
            x.Add(new XElement(xElement));

        }

        new XDocument(new XElement("ev", x)).Save(@"D:\output.xml");

Upvotes: 0

aush
aush

Reputation: 2108

In suppose you're not missing a root of your xml

var xDoc = // your XDocument
var toDel = new List<XElement>();
foreach(var el in xDoc.Root.Elements("Event").Where(e => e.Elements("SubEvent").All(xel => xel.Attribute("update").Value == "DATETIME")))
{
    toDel.Add(el);
}
toDel.ForEach(e => e.Remove());

You have to replace the condition inside .All() to desirable.

Upvotes: 0

Related Questions