簡體   English   中英

需要有關Linq XML條件分組查詢的幫助

[英]Need help with a Linq XML conditional grouping query

我有以下xml片段:

 <BANNER ID="Banner 2" ROW_WIDTH="200">
   <BANNER_TEXTS ID="BANNER_TEXTS">
    <BANNER_TEXT UNDERLINE="false" SPAN_COL="1" WIDTHT="78px"></BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="3" WIDTHT="234px">Years In Practice</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="3" WIDTHT="234px">Internet Usage</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="4" WIDTHT="312px">Sales  Reps Seen  / Week</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="3" WIDTHT="234px">Prescription Volume</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="3" WIDTHT="222px">Patient Load</BANNER_TEXT>
   </BANNER_TEXTS>
   <BANNER_TEXTS ID="COLUMN_TEXTS">
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="1" WIDTHT="78px">Total</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="1" WIDTHT="78px">&#60; 11 years</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="1" WIDTHT="78px">11-20 years</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="1" WIDTHT="78px">21-30 years</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="1" WIDTHT="78px">Light 1-5 hrs</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="1" WIDTHT="78px">Medium 6-10 hrs</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="1" WIDTHT="78px">Heavy &#62;10 hrs</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="1" WIDTHT="78px">0</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="1" WIDTHT="78px">1-2</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="1" WIDTHT="78px">3-5</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="1" WIDTHT="78px">&#62;5</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="1" WIDTHT="78px">1-100</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="1" WIDTHT="78px">101-150</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="1" WIDTHT="78px">&#62;150</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="1" WIDTHT="74px">1-100</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="1" WIDTHT="74px">101-200</BANNER_TEXT>
    <BANNER_TEXT UNDERLINE="true" SPAN_COL="1" WIDTHT="74px">&#62;200</BANNER_TEXT>
   </BANNER_TEXTS>
   <BANNER_TEXTS ID="COLUMN_TEXTS">
    <COLUMN_TEXT UNDERLINE="false" SPAN_COL="1">(A)</COLUMN_TEXT>
    <COLUMN_TEXT UNDERLINE="false" SPAN_COL="1">(B)</COLUMN_TEXT>
    <COLUMN_TEXT UNDERLINE="false" SPAN_COL="1">(C)</COLUMN_TEXT>
    <COLUMN_TEXT UNDERLINE="false" SPAN_COL="1">(D)</COLUMN_TEXT>
    <COLUMN_TEXT UNDERLINE="false" SPAN_COL="1">(E)</COLUMN_TEXT>
    <COLUMN_TEXT UNDERLINE="false" SPAN_COL="1">(F)</COLUMN_TEXT>
    <COLUMN_TEXT UNDERLINE="false" SPAN_COL="1">(G)</COLUMN_TEXT>
    <COLUMN_TEXT UNDERLINE="false" SPAN_COL="1">(H)</COLUMN_TEXT>
    <COLUMN_TEXT UNDERLINE="false" SPAN_COL="1">(I)</COLUMN_TEXT>
    <COLUMN_TEXT UNDERLINE="false" SPAN_COL="1">(J)</COLUMN_TEXT>
    <COLUMN_TEXT UNDERLINE="false" SPAN_COL="1">(K)</COLUMN_TEXT>
    <COLUMN_TEXT UNDERLINE="false" SPAN_COL="1">(L)</COLUMN_TEXT>
    <COLUMN_TEXT UNDERLINE="false" SPAN_COL="1">(M)</COLUMN_TEXT>
    <COLUMN_TEXT UNDERLINE="false" SPAN_COL="1">(N)</COLUMN_TEXT>
    <COLUMN_TEXT UNDERLINE="false" SPAN_COL="1">(O)</COLUMN_TEXT>
    <COLUMN_TEXT UNDERLINE="false" SPAN_COL="1">(P)</COLUMN_TEXT>
    <COLUMN_TEXT UNDERLINE="false" SPAN_COL="1">(Q)</COLUMN_TEXT>
   </BANNER_TEXTS>
  </BANNER>

我想使用第一個序列“ BANNER_TEXT”作為鍵將第二個序列中的所有“ BANNER_TEXT”分組(僅包括string不為null或為空的元素)。 第一個“ BANNER_TEXT”序列中的span_col屬性指示在第二個序列中按位置相關的元素。

例如:“ Years in Practice”將是第一個關鍵字,並且該元素的屬性SPAN_COL = 3表示它將包含“ <11年”,“ 11-20年”,“ 21-30年”( string.empty =>總計將被跳過)。

我已經能夠提出:

   IEnumerable<XElement> groupCats = child.Descendants("BANNER_TEXTS").ElementAt(0).Descendants("BANNER_TEXT");

    var totals =
            from s in groupCats
            let span = int.Parse(s.Attribute("SPAN_COL").Value)

            group s by s.Value into grouped
            select new
            {
                GroupCategory = grouped.Key,
                Categories = child.Descendants("BANNER_TEXTS").ElementAt(1).Descendants("BANNER_TEXT").Skip(1).Take(1)
    };

我想跳過到目前為止的跨度之和,並按跨度。 我現在無法將'span'變量放入查詢中。

考慮如下例所示計算一個相關 (位置)。

public class TopTitle
{
  public int Span {get;set;}
  public string Value {get;set;}
  public int Position {get;set;}
}

public class SubTitle
{
  public int Span {get;set;}
  public string Value {get;set;}
  public int Position {get;set;}
}

//
List<Title> Titles = GetTitles();
List<SubTitle> SubTitles = GetSubTitles();
int i = 0;
Titles.ForEach(t =>
{
  t.Position = i;
  i += t.Span;
}
i = 0;
SubTitles.ForEach(st =>
{
  st.Position = i;
  i += st.Span;
}

var query =
  from t in Titles
  let sts =
    from st in SubTitles
    where t.Position <= st.Position
      && st.Position < (t.Position + t.Span)
  select st
  select new {Title = t, SubTitles = sts.ToList()};

也許您可以通過擴展條件選擇來利用以下內容:

public class Grouping
{
    public string Title { get; set; }
    public string Criteria { get; set; }
}


XmlDocument xDoc = new XmlDocument();

var First_Sequence = (from b in XElement.Load("Banners.xml").Elements("BANNER_TEXTS").First().Elements("BANNER_TEXT")
                              where b.Value != ""
                              select b);

var Second_Sequence = (from b in XElement.Load("Banners.xml").Elements("BANNER_TEXTS").Skip(1).First().Elements("BANNER_TEXT")
                               where b.Value != "Total"
                               select b).ToList();

List<Grouping> groups = new List<Grouping>();

int i = 0;
foreach (var item in First_Sequence)
{
    groups.Add(new Grouping { Title = item.Value, Criteria = (Second_Sequence.Skip(i).First().Value).ToString() });
    i++;
}

這應該將每個序列(標頭序列和值序列)迭代一次:

static IEnumerable<IGrouping<TFirst, TSecond>> Chunk<TFirst, TSecond>(
    IEnumerable<TFirst> source, 
    IEnumerable<TSecond> toChunk, 
    Func<TFirst, int> chunkSizeSelector)
{
    //error checking here
    using (var chunkItems = toChunk.GetEnumerator())
    {
        foreach (var key in source)
        {
            List<TSecond> items = new List<TSecond>();
            for (int itemsRemaining = chunkSizeSelector(key); itemsRemaining > 0; itemsRemaining--)
            {
                if (!chunkItems.MoveNext())
                    throw new ArgumentException("There are not enough items in toChunk to satisfy source.");
                items.Add(chunkItems.Current);
            }
            yield return new ChunkGrouping<TFirst, TSecond>(key, items);
        }
    }
}

internal class ChunkGrouping<TKey, TElement> : IGrouping<TKey, TElement>
{
    public ChunkGrouping(TKey key, IEnumerable<TElement> elements)
    {
        if (elements == null) throw new ArgumentNullException("elements");
        _key = key;
        _elements = elements;
    }

    private readonly TKey _key;
    private readonly IEnumerable<TElement> _elements;

    public TKey Key { get { return _key; } }

    IEnumerator<TElement> IEnumerable<TElement>.GetEnumerator()
    {
        return _elements.GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return _elements.GetEnumerator();
    }
}

然后,您可以將其用作:

foreach (var group in Chunk(child.Elements("BANNER_TEXTS").ElementAt(0).Elements(),
                            child.Elements("BANNER_TEXTS").ElementAt(1).Elements(),
                            xe => (int)xe.Attribute("SPAN_COL")))
{
    //do stuff with the elements
}

我最終使用了這個:

foreach (XElement child in e.Elements("BANNER"))
            {

                IEnumerable<XElement> groups = child.Descendants("BANNER_TEXTS").ElementAt(0).Descendants("BANNER_TEXT");

                var groupCats =
                from s in groups
                group s by s.Value into grouped
                select new
                {
                    GroupCategory = grouped.Key,
                    Categories = GetCategories(grouped.Key, child)
                };
            }

 private IEnumerable<string> GetCategories(string key, XElement parent)
    {
        int span = parent.Descendants("BANNER_TEXTS").ElementAt(0).Descendants("BANNER_TEXT").Where(x => x.Value == key).Select(x => int.Parse(x.Attribute("SPAN_COL").Value)).FirstOrDefault();
        IEnumerable<int> set = Series(key,parent.Descendants("BANNER_TEXTS").ElementAt(0).Descendants("BANNER_TEXT"));
        int sum = set.Sum();        
        return parent.Descendants("BANNER_TEXTS").ElementAt(1).Descendants("BANNER_TEXT").Skip(sum).Take(span).Select(x => x.Value);

    }

    private static IEnumerable<int> Series(string key, IEnumerable<XElement> elements)
    {

        foreach (XElement item in elements)
        {
            if (item.Value != key)
            {
                yield return int.Parse(item.Attribute("SPAN_COL").Value);

            }
            else
            {
                break;
            }

        }

    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM