Linq-to-xml группируется по элементам, которые не имеют дочерних элементов - PullRequest
2 голосов
/ 17 ноября 2011

Мне было интересно, может ли кто-нибудь помочь со следующим:

У меня есть XML-документ, подобный этому:

<div class="_cl">element description 1</div>
<div class="_cl">
    <anotherele>dtls</anotherele>
    <anotherele>moredtls</anotherele>
</div>
<div class="_cl">
    <anotherele>dtls</anotherele>
    <anotherele>moredtls</anotherele>
</div>
<div class="_cl">element description 2</div>
<div class="_cl">
    <anotherele>dtls</anotherele>
    <anotherele>moredtls</anotherele>
</div>
<div class="_cl">
    <anotherele>dtls</anotherele>
    <anotherele>moredtls</anotherele>
</div>

Мне было интересно, есть ли способ в linq сгруппировать это по элементам, которые не имеют дочерних элементов. В основном, пытаясь структурировать документ как-то так:

<div class="_cl">element description 1
   <div class="_cl">
       <anotherele>dtls</anotherele>
       <anotherele>moredtls</anotherele>
   </div>
   <div class="_cl">
       <anotherele>dtls</anotherele>
       <anotherele>moredtls</anotherele>
   </div>
</div>
<div class="_cl">element description 2
   <div class="_cl">
       <anotherele>dtls</anotherele>
       <anotherele>moredtls</anotherele>
   </div>
   <div class="_cl">
       <anotherele>dtls</anotherele>
       <anotherele>moredtls</anotherele>
   </div>
</div>

Моя первая неудачная попытка выглядит так:

var n = from a in doc.Descendants()
                where a.Name.LocalName == "div" && (string)a.Attribute("class") == "_cl"
                group a by a.Value.Length<50 into g 
                select new { k = g.Key, p = g.Count() };

Надеюсь, что это имеет смысл, и спасибо заранее.

Stu

Ответы [ 3 ]

1 голос
/ 17 ноября 2011

Вот пример, предполагая, что ввод

<body>
<div class="_cl">element description 1</div>
<div class="_cl">
  <anotherele>dtls</anotherele>
  <anotherele>moredtls</anotherele>
</div>
<div class="_cl">
  <anotherele>dtls</anotherele>
  <anotherele>moredtls</anotherele>
</div>
<div class="_cl">element description 2</div>
<div class="_cl">
  <anotherele>dtls</anotherele>
  <anotherele>moredtls</anotherele>
</div>
<div class="_cl">
  <anotherele>dtls</anotherele>
  <anotherele>moredtls</anotherele>
</div>
</body>

, затем код

    XDocument input = XDocument.Load("input.xml");

    XDocument output = new XDocument(
        new XElement(input.Root.Name,
            from el in input.Root.Elements()
            where el.Elements().Any()
            group el by el.NodesBeforeSelf().OfType<XElement>().LastOrDefault(e => !e.Elements().Any()) into g
            select new XElement(g.Key.Name,
                g.Key.Attributes(),
                g.Key.Nodes(),
                g)
            ));

    output.Save(Console.Out);

вывод

<body>
  <div class="_cl">element description 1<div class="_cl"><anotherele>dtls</anoth
erele><anotherele>moredtls</anotherele></div><div class="_cl"><anotherele>dtls</anotherele><anotherele>moredtls</anotherele></div></div>
  <div class="_cl">element description 2<div class="_cl"><anotherele>dtls</anoth
erele><anotherele>moredtls</anotherele></div><div class="_cl"><anotherele>dtls</anotherele><anotherele>moredtls</anotherele></div></div>
</body>

Это то, что вы хотите, я думаю, за исключением отступа.Что касается отступа, вы можете приблизиться к желаемому результату, загрузив ввод с помощью XDocument.Load("input.xml", LoadOptions.PreserveWhitespace).

Подробнее об этом подходе к группировке см. http://msmvps.com/blogs/martin_honnen/archive/2009/11/27/grouping-with-linq-to-xml.aspx.

0 голосов
/ 21 ноября 2011

Спасибо за ваш вклад, но ни одно из решений, похоже, не позволяет его сократить. Я думаю, что я буду делать, просто перебирать элементы и анализировать их вручную. Я просто думал, что хороший linq однострочный будет лучше.

Приветствия

Stu

0 голосов
/ 17 ноября 2011

Сварог прав; то, что вы пытаетесь сделать, не может быть достигнуто путем группировки. Вам потребуются более сложные выражения Linq, чем указано в ключевых словах Linq.

Попробуйте это:

var n = doc.Elements().Where(div=>!div.Elements().Any()).
        Select(div=>{
            div.Add(
                div.ElementsAfterSelf().TakeWhile(x=>x.Elements().Any())
            ); 
            return div;
        }); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...