c# - 使用带有 MVC 的 C# 将 CSS 扁平化为 HTML

标签 c# html css

我在从 HTML 创建电子邮件并让它们在 Outlook 中正确显示时遇到了一个小问题。

现在我们都知道 Outlook 的 HTML 呈现有些差。 (客气一点!)基本上,最好的方法是将样式融入 HTML 元素中。但是,我想获取现有的基于网络的报告并将其通过电子邮件发送出去。显然,报告是使用来自 CSS 类的样式正确完成的。

所以我需要做的是解析 HTML 页面和 CSS 并构建一个扁平化的 HTML 片段,我可以将其邮寄出去。

使用 JavaScript 和 jQuery 这会相对简单,类似于

$("td.baddata").attr("style", "color:red");

当您遍历 CSS 时,显然会更改选择器和样式值。

在研究这个问题时,我偶然发现了 Html Agility Pack ,但是我在文档方面找不到太多,所以不知道你是否可以做上面那样的事情,并且宁愿不花时间去学习它是如何工作的,只是为了发现它不适合工作.例如,它可以根据上面的选择器返回元素集合吗? (大概我需要一个 DOM 选择器到 XPath 转换器?)

最佳答案

所以在四处寻找了一段时间并没有找到任何明显可以满足我的要求之后,我选择了 HTML Agility Pack。并制作了我自己的“CSS 到 HTML 扁平化器”。它采用原始样式文本并将其应用于 HTML 正文。

请注意,这是非常未经测试的,使用了各种肮脏的东西,而且可能有更好的方法来做很多事情。它也不能处理很多 CSS,尤其是“:selectors”,但它目前可以满足我的需要,所以我很高兴。

    public static string FlattenCssIntoHtml(string html)
    {
        Regex styleReg = new Regex(@"(.*?)\{(.*?)\}$", RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.CultureInvariant);
        Regex cssReg = new Regex(@"(.*?):(.*?)$", RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.CultureInvariant);
        HtmlDocument doc = new HtmlDocument();
        doc.LoadHtml(html);

        IEnumerable<HtmlNode> styleNode = doc.DocumentNode.SelectNodes("html[1]/head[1]/style[1]");

        // replace \r's as RegEx only matches \n to newline.
        foreach (Match match in styleReg.Matches(styleNode.First().InnerText.Replace("\r", "")))
        {
            if (match.Groups.Count == 3)
            {
                List<HtmlNode> toSet = FindNodes(doc.DocumentNode.SelectSingleNode("html[1]/body[1]"), match.Groups[1].Value.Trim().Split(' '), 0);

                foreach (Match cssMatch in cssReg.Matches(match.Groups[2].Value))
                {
                    foreach (HtmlNode thisNode in toSet)
                    {
                        AddStyle(thisNode, cssMatch.Groups[1].Value.Trim(), cssMatch.Groups[2].Value.Trim());
                    }
                }
            }
        }

        return doc.DocumentNode.OuterHtml;
    }

    private static List<HtmlNode> FindNodes(HtmlNode topNode, string[] toParse, int index)
    {
        IEnumerable<HtmlNode> myList;
        string selector = toParse[index];
        string elementName = "";
        string valueName = "";
        int valueType = 0;

        int idx = selector.IndexOfAny(new[] { '.', '#' });
        if (idx > -1)
        {
            elementName = selector.Substring(0, idx);
            valueName = selector.Substring(idx + 1);
            valueType = selector.Substring(idx, 1) == "." ? 1 : 2;
        }
        else
        {
            elementName = selector;
        }

        switch (valueType)
        {
            case 0:
                myList = topNode.Descendants().Where(x => x.Name == elementName);
                break;
            case 1:
                myList = topNode.Descendants().Where(x => (elementName == "" || x.Name == elementName) && x.Attributes.Contains("class") && x.Attributes["class"].Value.Split().Contains(valueName));
                break;
            case 2:
                myList = topNode.Descendants().Where(x => (elementName == "" || x.Name == elementName) && x.Id == valueName);
                break;
            default:
                throw new NotImplementedException();
        }

        if (index == toParse.Length - 1)
        {
            return new List<HtmlNode>(myList);
        }

        List<HtmlNode> toReturn = new List<HtmlNode>();
        foreach (HtmlNode aNode in myList)
        {
            toReturn.AddRange(FindNodes(aNode, toParse, index + 1));
        }
        return toReturn;
    }

    private static void AddStyle(HtmlNode dest, string styleName, string styleValue)
    {
        if (!dest.Attributes.Contains("style"))
        {
            dest.Attributes.Add("style", styleName + ":" + styleValue);
        }
        else
        {
            HtmlAttribute attr = dest.Attributes["style"];

            if (!attr.Value.Split().Contains(styleName))
            {
                attr.Value = attr.Value + " " +  styleName + ":" + styleValue;
            }
        }
    }

关于c# - 使用带有 MVC 的 C# 将 CSS 扁平化为 HTML,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21533536/

相关文章:

javascript - 我想让播放栏始终可见,但只有在悬停时才可见

javascript - 在不使用 JQuery 的情况下使用 math.random 通过单选按钮移动 div

javascript - 我的 gulp.js 文件没有在浏览器上更新我的 css

c# - IEnumerable<dynamic> 上的 LINQ Select 编译时错误

c# - 我怎样才能找出是什么在制造垃圾?

c# - DisplayNameFor 用于从 IEnumerable<T> 派生的接口(interface)

html - 悬停时增加高度并插入元素顶部和底部

html - CSS3 : increase tooltip div height to upwards

c# - C# 6 中(自动)属性初始化语法之间的区别

html - 选择在 CSS 中具有相同类的另一个元素之前的元素