迭代问题 - 附加开头和结尾的html

时间:2011-09-22 23:54:12

标签: c#

我正在试图找出如何只在这里附加开头和关闭div和ul。我不知道如何将下一个字符串与ParentName的当前值进行比较:

    foreach (SList subList in parentList)
    {
        if (subList.SubList.Count < 1)
            return string.Empty;

        for(int i = 0; i < subList.SubList.Count; i++)
        {
            if (string.Compare(subList.PName, lastPName) != 0)
            {
                subListItemsToHtml.AppendFormat(@"<div id='{0}-test' class='dropdown'>", subList.SubList[i].PName);
                subListItemsToHtml.Append("<ul>");
            }

            subListItemsToHtml.AppendFormat(@"    <li><a href='{0}'>{1}</a></li>", subList.SubList[i].URL, subList.SubList[i].DisplayName);
            lastPName = subList.SubList[i].PName;

            if (i + 1 < subList.SubList.Count)
                if(string.Compare(subList.SubList[i].PName, subList.SubList[i+1].PName) != 0)
                    subListItemsToHtml.Append("</ul></div>");
        }
    }


    return subListItemsToHtml.ToString();
}

3 个答案:

答案 0 :(得分:0)

我不知道您的数据结构是否与标记的结构相匹配,但如果它匹配则更改为这似乎是合乎逻辑的:

foreach (SList subList in parentList)
{
    if (subList.SubList.Count < 1)
        return string.Empty;

    subListItemsToHtml.AppendFormat(@"<div id='{0}-test' class='dropdown'>", subList.SubList[i].PName);
    subListItemsToHtml.Append("<ul>");

    for(int i = 0; i < subList.SubList.Count; i++)
    {
        subListItemsToHtml.AppendFormat(@"    <li><a href='{0}'>{1}</a></li>", subList.SubList[i].URL, subList.SubList[i].DisplayName);
        lastPName = subList.SubList[i].PName;
    }

    subListItemsToHtml.Append("</ul></div>");
}

return subListItemsToHtml.ToString();

就个人而言,我更倾向于使用LINQ和LINQ to XML来预测数据。这也将避免潜在的格式错误的HTML(您通过字符串连接构建HTML而无需HTML转义输出):

var xhtml = new XDocument(
    new XElement("div",
        from subList in parentList
        where subList.SubList.Count > 0
        select new XElement("div",
            new XAttribute("id", subList.SubList[0].PName + "-test"),
            new XAttribute("class", "dropdown"),
            new XElement("ul",
                from child in subList
                select new XElement("li",
                    new XElement("a",
                        new XAttribute("href", child.URL),
                        new XText(child.DisplayName)))))));
return xhtml.ToString();

答案 1 :(得分:0)

尝试按如下方式重新编码代码:

foreach (SList subList in parentList)
{
    if (subList.SubList.Count < 1)
        return string.Empty;

    for(int i = 0; i < subList.SubList.Count; i++)
    {
        if (string.Compare(subList.PName, lastPName) != 0)
        {
            subListItemsToHtml.AppendFormat(@"<div id='{0}-test' class='dropdown'>", subList.SubList[i].PName);
            subListItemsToHtml.Append("<ul>");

            subListItemsToHtml.AppendFormat(@"    <li><a href='{0}'>{1}</a></li>", subList.SubList[i].URL, subList.SubList[i].DisplayName);
            subListItemsToHtml.Append("</ul></div>");
        }
        else
        {
            subListItemsToHtml.AppendFormat(@"    <li><a href='{0}'>{1}</a></li>", subList.SubList[i].URL, subList.SubList[i].DisplayName);
        }
        lastPName = subList.SubList[i].PName;
    }
}

答案 2 :(得分:0)

如果有一个子列表子列表是正确的,我对你的问题不确定吗?

看起来你的结构是这样的:

public class Parent : List<SList>
{ }

public class SList
{
    public List<SList> SubList = new List<SList>();
    public string PName;
    public string URL;
    public string DisplayName;
}

在您的代码中,您将顶级子列表的PName与每个孩子的子列表PName进行比较,这对我来说似乎不对。也许你可以解释一下你的结构?

尽管如此,如果我认为您可以将parentList数据展平为IEnumerable<SList>,那么我会为您提供解决方案。

首先,我像这样展平parentList数据:

var sublists =
    from subList in parentList
    from subList2 in subList.SubList
    select subList2;

然后我执行以下操作:

var html = String.Join(Environment.NewLine,
    sublists
        .AdjacentBy(
            sl => sl.PName,
            sls => String.Format(@"<div id='{0}-test' class='dropdown'><ul>",
                sls.First().PName),
            sl => String.Format(@"<li><a href='{0}'>{1}</a></li>",
                sl.URL,
                sl.DisplayName),
            sls => @"</ul></div>")
        .SelectMany(x => x));

这会产生你的html,它应该与此相当:

var html = @"<div id='foo1a-test' class='dropdown'><ul>
<li><a href='url1a'>bar1a</a></li>
</ul></div>
<div id='goo1b-test' class='dropdown'><ul>
<li><a href='url1b'>bar1b</a></li>
<li><a href='url2a'>bar2a</a></li>
</ul></div>
<div id='foo2b-test' class='dropdown'><ul>
<li><a href='url2b'>bar2b</a></li>
</ul></div>";

现在,我确信你发现了使用新的扩展方法AdjacentBy。这就是所有魔法发生的地方。

我非常希望将您正在进行的操作抽象为一个可重用的LINQ运算符。这样做意味着执行生成HTML工作的代码简洁明了,与迭代列表和分组结果的繁琐工作分开。

AdjacentBy的签名如下所示:

IEnumerable<IEnumerable<V>> AdjacentBy<T, K, V>(
    this IEnumerable<T> source,
    Func<T, K> keySelector,
    Func<IEnumerable<T>, V> headerSelector,
    Func<T, V> valueSelector,
    Func<IEnumerable<T>, V> footerSelector)

它的工作是在keySelector产生的值发生变化时获取列表并列出列表。列表列表中的值来自valueSelector

headerSelector&amp; footerSelector lambdas可用于根据当前列表中的项创建页眉值和页脚值。

因此,举例来说,如果我运行此查询:

var query = "CBBCCA"
    .AdjacentBy(
        c => c,
        cs => cs.Count().ToString() + "x",
        c => c.ToString(),
        cs => ".")
    .ToArray();

它将相当于:

var query = new []
{
    new [] { "1x", "C", "." },
    new [] { "2x", "B", "B", "." },
    new [] { "2x", "C", "C", "." },
    new [] { "1x", "A", "." },
};

以下是AdjacentBy的完整定义:

public static IEnumerable<IEnumerable<V>> AdjacentBy<T, K, V>(
    this IEnumerable<T> source,
    Func<T, K> keySelector,
    Func<IEnumerable<T>, V> headerSelector,
    Func<T, V> valueSelector,
    Func<IEnumerable<T>, V> footerSelector)
{
    var first = true;
    var last = default(K);
    var list = new List<T>();
    var values = (IEnumerable<V>)null;
    Func<List<T>, IEnumerable<V>> getValues = ts =>
    {
        var vs = (IEnumerable<V>)null;
        if (ts.Count > 0)
        {
            IEnumerable<V> hs = headerSelector == null
                ? Enumerable.Empty<V>()
                : new [] { headerSelector(ts) };
            IEnumerable<V> fs = footerSelector == null
                ? Enumerable.Empty<V>()
                : new [] { footerSelector(ts) };
            vs = hs
                .Concat(ts.Select(t => valueSelector(t)))
                .Concat(fs)
                .ToArray();
        }
        return vs;
    };
    foreach (var t in source)
    {
        var current = keySelector(t);
        if (first || !current.Equals(last))
        {
            first = false;
            values = getValues(list);
            if (values != null)
            {
                yield return values;
            }
            list.Clear();
            last = current;
        }
        list.Add(t);
    }
    values = getValues(list);
    if (values != null)
    {
        yield return values;
    }
}

我希望这会有所帮助。