在C#中的内联CSS [英] Inlining CSS in C#

查看:143
本文介绍了在C#中的内联CSS的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要从C#中的样式表内联CSS。

怎么样工作的。

<一个href=\"http://www.mailchimp.com/labs/inlinecss.php\">http://www.mailchimp.com/labs/inlinecss.php

CSS的简单,只需班,没有花哨的选择。

我使用的是正则表达式考虑(小于?规则&GT;(&LT;选择&GT; [^ {}] +){(LT;风格&GT; [^ {}] +)}) + 从CSS剥离规则,然后试图做简单的字符串替换所在班被称为,但一些HTML元素已经有一个风格的标签,所以我必须考虑这点。

有没有更简单的方法呢?什么已经写在C#?

更新 - 2010年9月16日

我已经能够拿出一个简单的CSS内联提供你的HTML也是有效的XML。它使用正则表达式来帮助你在&LT所有样式,风格/&GT; 元素。然后转换CSS选择器与XPath前pressions,并增加了风格的行内的匹配元素,任何pre-现有内嵌样式之前。

请注意,该CssToXpath没有完全落实,有一些东西,它只是不能做......呢。

CssInliner.cs

 使用System.Collections.Generic;
使用System.Text.RegularEx pressions;
使用System.Xml.Linq的;
使用System.Xml.XPath;命名空间CssInliner
{
    公共类CssInliner
    {
        私有静态正则表达式_matchStyles =新的正则表达式(\\\\ S *(&LT;规则&GT;(&LT;选择&GT; [^ {}] +){(LT;风格&GT; [^ {}] +)}),
                                                RegexOptions.IgnoreCase
                                                | RegexOptions.CultureInvariant
                                                | RegexOptions.IgnorePatternWhitespace
                                                | RegexOptions.Compiled
                                            );        公开名单&LT;匹配和GT;样式{搞定;私人集; }
        公共字符串InlinedXhtml {搞定;私人集; }        私人的XElement XhtmlDocument {搞定;组; }        公共CssInliner(字符串XHTML)
        {
            XhtmlDocument = ParseXhtml(XHTML);
            样式= GetStyleMatches();            的foreach(在样式VAR风格)
            {
                如果(!style.Success)
                    返回;                VAR cssSelector = style.Groups [选择] Value.Trim()。
                VAR xpathSelector = CssToXpath.Transform(cssSelector);
                VAR cssStyle = style.Groups [风格] Value.Trim()。                的foreach(在XhtmlDocument.XPathSelectElements VAR元素(xpathSelector))
                {
                    VAR inlineStyle = element.Attribute(风格);                    变种newInlineStyle = cssStyle +;;
                    如果(inlineStyle = NULL&放大器;!&安培;!string.IsNullOrEmpty(inlineStyle.Value))
                    {
                        newInlineStyle + = inlineStyle.Value;
                    }                    element.SetAttributeValue(风格,newInlineStyle.Trim()NormalizeCharacter(';')。NormalizeSpace());
                }
            }            。XhtmlDocument.Descendants(风格),删除();
            InlinedXhtml = XhtmlDocument.ToString();
        }        私人列表&LT;匹配和GT; GetStyleMatches()
        {
            VAR风格=新的List&LT;匹配和GT;();            VAR styleElements = XhtmlDocument.Descendants(风格);
            的foreach(在styleElements VAR styleElement)
            {
                VAR匹配= _matchStyles.Matches(styleElement.Value);                的foreach(在比赛中赛赛)
                {
                    styles.Add(匹配);
                }
            }            返回的款式;
        }        私有静态的XElement ParseXhtml(字符串XHTML)
        {
            返回XElement.Parse(XHTML);
        }
    }
}

CssToXpath.cs

 使用System.Text.RegularEx pressions;命名空间CssInliner
{
    公共静态类CssToXpath
    {
        公共静态字符串变换(字符串的CSS)
        {
            #区域转换规则
            //参考文献:http://ejohn.org/blog/xpath-css-selectors/
            // HTTP://$c$c.google.com/p/css2xpath/source/browse/trunk/src/css2xpath.js
            VAR regexReplaces =新[] {
                                          // @添加为attribs
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@\\ [([^ \\]〜\\ $​​ \\ * \\ ^ \\ |!\\] +)(= [^ \\]] +)\\]?,RegexOptions.Multiline)
                                              替换= @[@ $ 1 $ 2]
                                          },
                                          //多个查询
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@\\ S * \\ S *,RegexOptions.Multiline)
                                              替换= @|
                                          },
                                          // +〜&GT;
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@\\ S *(\\ + |〜|&GT;)\\ S *,RegexOptions.Multiline)
                                              替换= @$ 1
                                          },
                                          // *〜+&GT;
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@([A-ZA-Z0-9 _ \\ - \\ *])〜([A-ZA-Z0-9 _ \\ - \\ *]),RegexOptions.Multiline)
                                              替换= @$ 1 /以下同胞:: $ 2
                                          },
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@([A-ZA-Z0-9 _ \\ - \\ *])\\ +([A-ZA-Z0-9 _ \\ - \\ *]),RegexOptions.Multiline)
                                              替换= @$ 1 /以下同胞:: * [1] /自:: $ 2
                                          },
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@([A-ZA-Z0-9 _ \\ - \\ *])&GT;([A-ZA-Z0-9 _ \\ - \\ *]),RegexOptions.Multiline)
                                              替换= @$ 1 / $ 2
                                          },
                                          //所有转义东西逃跑
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@\\ [([^ =] +)=([^|] [^ \\] *)\\],RegexOptions.Multiline)
                                              替换= @[$ 1 = $ 2']
                                          },
                                          //所有后代或自我//
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@(^ | [^ A-ZA-Z0-9 _ \\ - \\ *])(#| \\)([A-ZA-Z0-9 _ \\ - ] +),RegexOptions.Multiline )
                                              替换= @$ 1 * $ 2 $ 3
                                          },
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@([\\&GT; \\ + \\ | \\〜\\,\\ S])([A-ZA-Z \\ *] +),RegexOptions.Multiline)
                                              替换= @$ 1 // $ 2
                                          },
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@\\ S + \\ / \\ /,RegexOptions.Multiline)
                                              替换= @//
                                          },
                                          //:第一个孩子
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@([A-ZA-Z0-9 _ \\ - \\ *] +):第一胎,RegexOptions.Multiline)
                                              替换= @* [1] /自:: $ 1
                                          },
                                          // :最后一个孩子
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@([A-ZA-Z0-9 _ \\ - \\ *] +):最后一子,RegexOptions.Multiline)
                                              替换= @$ 1 [未(以下同胞:: *)]
                                          },
                                          // :唯一的孩子
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@([A-ZA-Z0-9 _ \\ - \\ *] +):独生子女,RegexOptions.Multiline)
                                              替换= @* [最后的()= 1] /自:: $ 1
                                          },
                                          //:空
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@([A-ZA-Z0-9 _ \\ - \\ *] +):空,RegexOptions.Multiline)
                                              替换= @$ 1 [否(*)和不(正常化空间())]
                                          },
                                          // | = ATTRIB
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@\\ [(A-ZA-Z0-9 _ \\ - ] +)\\ | =([^ \\]] +)\\],RegexOptions.Multiline)
                                              替换= @[@ $ 1 = $ 2或开始 - 有(1 @ $,CONCAT($ 2, - ))
                                          },
                                          // * = ATTRIB
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@\\ [(A-ZA-Z0-9 _ \\ - ] +)\\ * =([^ \\]] +)\\],RegexOptions.Multiline)
                                              替换= @[包含(@ $ 1,$ 2)]
                                          },
                                          //〜= ATTRIB
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@\\ [(A-ZA-Z0-9 _ \\ - ] +)〜=([^ \\]] +)\\],RegexOptions.Multiline)
                                              [('CONCAT(',规范空间(@ $ 1),''),CONCAT(',$ 2,''))含有]替换= @
                                          },
                                          // ^ = ATTRIB
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@\\ [(A-ZA-Z0-9 _ \\ - ] +)\\ ^ =([^ \\]] +)\\],RegexOptions.Multiline)
                                              替换= @[开始-用(@ $ 1,$ 2)]
                                          },
                                          //!= ATTRIB
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@\\ [(A-ZA-Z0-9 _ \\ - ] +)\\ =([^ \\]] +)\\],RegexOptions.Multiline)
                                              替换= @[未(@ $ 1)或@ $ 1!= $ 2]
                                          },
                                          // IDS
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@#([A-ZA-Z0-9 _ \\ - ] +),RegexOptions.Multiline)
                                              替换= @[@ ID ='$ 1']
                                          },
                                          //类
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@\\([A-ZA-Z0-9 _ \\ - ] +),RegexOptions.Multiline)
                                              [('CONCAT(',规范空间(@class),''),'$ 1')含有]替换= @
                                          },
                                          //正常化多个过滤器
                                          新REGEXREPLACE {
                                              正则表达式=新的正则表达式(@\\] \\ [([^ \\]] +),RegexOptions.Multiline)
                                              替换= @和($ 1)
                                          },                                      };
            #endregion            的foreach(在regexReplaces VAR REGEXREPLACE)
            {
                CSS = regexReplace.Regex.Replace(CSS,regexReplace.Replace);
            }            返回//+ CSS;
        }
    }    结构REGEXREPLACE
    {
        公共正则表达式正则表达式;
        公共字符串替换;
    }
}

和一些测试

  [TestMethod的]
    公共无效TestCssToXpathRules()
    {
        VAR翻译=新词典&LT;字符串,字符串&GT;
                               {
                                   {*,// *},
                                   {P,// p的},
                                   {P&GT; *,// P / *},
                                   {#foo,// * [@ ID ='富']},
                                   {* [标题],// * [@标题]},
                                   {的.bar​​,// * [含有(的concat('',正常化空间(@class),''),巴')]},
                                   {#DIV测试。注意跨度:第一子,// DIV [@ ID ='测试'// * [包含(CONCAT('',规范空间(@class),''),'注意')] // * [1] /自::跨度}
                               };        的foreach(在翻译VAR译)
        {
            VAR预期= translation.Value;
            VAR的结果= CssInliner.CssToXpath.Transform(translation.Key);            Assert.AreEqual(预期结果);
        }
    }    [测试方法]
    公共无效HtmlWithMultiLineClassStyleReturnsInline()
    {
        #地区的VAR HTML = ...
        VAR HTML = XElement.Parse(@&LT; HTML和GT;
                                        &LT; HEAD&GT;
                                            &LT;标题&GT;的Hello,World页&LT;!/标题&GT;
                                            &LT;风格&GT;
                                                .redClass {
                                                    背景:红色;
                                                    颜色:紫色;
                                                }
                                            &LT; /风格&GT;
                                        &LT; /头&GT;
                                        &LT;身体GT;
                                            &LT; D​​IV CLASS =redClass&GT;的Hello,World&LT;!/ DIV&GT;
                                        &LT; /身体GT;
                                    &LT; / HTML方式&gt;)的ToString();
        #endregion        #地区常量字符串预期...
        VAR预期= XElement.Parse(@&LT; HTML和GT;
                                            &LT; HEAD&GT;
                                                &LT;标题&GT;的Hello,World页&LT;!/标题&GT;
                                            &LT; /头&GT;
                                            &LT;身体GT;
                                                &LT; D​​IV CLASS =redClass的风格=背景:红色;颜色:紫色;&GT;的Hello,World&LT; / DIV&GT;
                                            &LT; /身体GT;
                                        &LT; / HTML方式&gt;)的ToString();
        #endregion        VAR的结果=新CssInliner.CssInliner(HTML);        Assert.AreEqual(预期,result.InlinedXhtml);
    }

有更多的测试,但是,它们导入HTML文件的输入和预期的输出,我不张贴所有!

但我应该张贴的规范化扩展方法!

 私有静态只读正则表达式NormalizeSpaceRegex ​​=新的正则表达式(@\\ s {2},RegexOptions.None);
公共静态字符串NormalizeSpace(此字符串数据)
{
    返回NormalizeSpaceRegex.Replace(数据,@);
}公共静态字符串NormalizeCharacter(这串数据,CHAR字符)
{
    VAR normalizeCharacterRegex ​​=新的正则表达式(字符+{2},RegexOptions.None);
    返回normalizeCharacterRegex.Replace(数据,character.ToString());
}


解决方案

既然你已经用你的当前实现,你为什么不使用现有的框架,但替换XML与HTML解析的方式出现90%解析器呢?其中一个比较流行的在那里是 HTML敏捷性包的。它支持XPath查询,甚至有一个LINQ界面类似规定的XML所以它应该是一个相当简单的更换标准的.NET接口。

I need to inline css from a stylesheet in c#.

Like how this works.

http://www.mailchimp.com/labs/inlinecss.php

The css is simple, just classes, no fancy selectors.

I was contemplating using a regex (?<rule>(?<selector>[^{}]+){(?<style>[^{}]+)})+ to strip the rules from the css, and then attempting to do simple string replaces where the classes are called, but some of the html elements already have a style tag, so I'd have to account for that as well.

Is there a simpler approach? Or something already written in c#?

UPDATE - Sep 16, 2010

I've been able to come up with a simple CSS inliner provided your html is also valid xml. It uses a regex to get all the styles in your <style /> element. Then converts the css selectors to xpath expressions, and adds the style inline to the matching elements, before any pre-existing inline style.

Note, that the CssToXpath is not fully implemented, there are some things it just can't do... yet.

CssInliner.cs

using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using System.Xml.XPath;

namespace CssInliner
{
    public class CssInliner
    {
        private static Regex _matchStyles = new Regex("\\s*(?<rule>(?<selector>[^{}]+){(?<style>[^{}]+)})",
                                                RegexOptions.IgnoreCase
                                                | RegexOptions.CultureInvariant
                                                | RegexOptions.IgnorePatternWhitespace
                                                | RegexOptions.Compiled
                                            );

        public List<Match> Styles { get; private set; }
        public string InlinedXhtml { get; private set; }

        private XElement XhtmlDocument { get; set; }

        public CssInliner(string xhtml)
        {
            XhtmlDocument = ParseXhtml(xhtml);
            Styles = GetStyleMatches();

            foreach (var style in Styles)
            {
                if (!style.Success)
                    return;

                var cssSelector = style.Groups["selector"].Value.Trim();
                var xpathSelector = CssToXpath.Transform(cssSelector);
                var cssStyle = style.Groups["style"].Value.Trim();

                foreach (var element in XhtmlDocument.XPathSelectElements(xpathSelector))
                {
                    var inlineStyle = element.Attribute("style");

                    var newInlineStyle = cssStyle + ";";
                    if (inlineStyle != null && !string.IsNullOrEmpty(inlineStyle.Value))
                    {
                        newInlineStyle += inlineStyle.Value;
                    }

                    element.SetAttributeValue("style", newInlineStyle.Trim().NormalizeCharacter(';').NormalizeSpace());
                }
            }

            XhtmlDocument.Descendants("style").Remove();
            InlinedXhtml = XhtmlDocument.ToString();
        }

        private List<Match> GetStyleMatches()
        {
            var styles = new List<Match>();

            var styleElements = XhtmlDocument.Descendants("style");
            foreach (var styleElement in styleElements)
            {
                var matches = _matchStyles.Matches(styleElement.Value);

                foreach (Match match in matches)
                {
                    styles.Add(match);
                }
            }

            return styles;
        }

        private static XElement ParseXhtml(string xhtml)
        {
            return XElement.Parse(xhtml);
        }
    }
}

CssToXpath.cs

using System.Text.RegularExpressions;

namespace CssInliner
{
    public static class CssToXpath
    {
        public static string Transform(string css)
        {
            #region Translation Rules
            // References:  http://ejohn.org/blog/xpath-css-selectors/
            //              http://code.google.com/p/css2xpath/source/browse/trunk/src/css2xpath.js
            var regexReplaces = new[] {
                                          // add @ for attribs
                                          new RegexReplace {
                                              Regex = new Regex(@"\[([^\]~\$\*\^\|\!]+)(=[^\]]+)?\]", RegexOptions.Multiline),
                                              Replace = @"[@$1$2]"
                                          },
                                          //  multiple queries
                                          new RegexReplace {
                                              Regex = new Regex(@"\s*,\s*", RegexOptions.Multiline),
                                              Replace = @"|"
                                          },
                                          // , + ~ >
                                          new RegexReplace {
                                              Regex = new Regex(@"\s*(\+|~|>)\s*", RegexOptions.Multiline),
                                              Replace = @"$1"
                                          },
                                          //* ~ + >
                                          new RegexReplace {
                                              Regex = new Regex(@"([a-zA-Z0-9_\-\*])~([a-zA-Z0-9_\-\*])", RegexOptions.Multiline),
                                              Replace = @"$1/following-sibling::$2"
                                          },
                                          new RegexReplace {
                                              Regex = new Regex(@"([a-zA-Z0-9_\-\*])\+([a-zA-Z0-9_\-\*])", RegexOptions.Multiline),
                                              Replace = @"$1/following-sibling::*[1]/self::$2"
                                          },
                                          new RegexReplace {
                                              Regex = new Regex(@"([a-zA-Z0-9_\-\*])>([a-zA-Z0-9_\-\*])", RegexOptions.Multiline),
                                              Replace = @"$1/$2"
                                          },
                                          // all unescaped stuff escaped
                                          new RegexReplace {
                                              Regex = new Regex(@"\[([^=]+)=([^'|""][^\]]*)\]", RegexOptions.Multiline),
                                              Replace = @"[$1='$2']"
                                          },
                                          // all descendant or self to //
                                          new RegexReplace {
                                              Regex = new Regex(@"(^|[^a-zA-Z0-9_\-\*])(#|\.)([a-zA-Z0-9_\-]+)", RegexOptions.Multiline),
                                              Replace = @"$1*$2$3"
                                          },
                                          new RegexReplace {
                                              Regex = new Regex(@"([\>\+\|\~\,\s])([a-zA-Z\*]+)", RegexOptions.Multiline),
                                              Replace = @"$1//$2"
                                          },
                                          new RegexReplace {
                                              Regex = new Regex(@"\s+\/\/", RegexOptions.Multiline),
                                              Replace = @"//"
                                          },
                                          // :first-child
                                          new RegexReplace {
                                              Regex = new Regex(@"([a-zA-Z0-9_\-\*]+):first-child", RegexOptions.Multiline),
                                              Replace = @"*[1]/self::$1"
                                          },
                                          // :last-child
                                          new RegexReplace {
                                              Regex = new Regex(@"([a-zA-Z0-9_\-\*]+):last-child", RegexOptions.Multiline),
                                              Replace = @"$1[not(following-sibling::*)]"
                                          },
                                          // :only-child
                                          new RegexReplace {
                                              Regex = new Regex(@"([a-zA-Z0-9_\-\*]+):only-child", RegexOptions.Multiline),
                                              Replace = @"*[last()=1]/self::$1"
                                          },
                                          // :empty
                                          new RegexReplace {
                                              Regex = new Regex(@"([a-zA-Z0-9_\-\*]+):empty", RegexOptions.Multiline),
                                              Replace = @"$1[not(*) and not(normalize-space())]"
                                          },
                                          // |= attrib
                                          new RegexReplace {
                                              Regex = new Regex(@"\[([a-zA-Z0-9_\-]+)\|=([^\]]+)\]", RegexOptions.Multiline),
                                              Replace = @"[@$1=$2 or starts-with(@$1,concat($2,'-'))]"
                                          },
                                          // *= attrib
                                          new RegexReplace {
                                              Regex = new Regex(@"\[([a-zA-Z0-9_\-]+)\*=([^\]]+)\]", RegexOptions.Multiline),
                                              Replace = @"[contains(@$1,$2)]"
                                          },
                                          // ~= attrib
                                          new RegexReplace {
                                              Regex = new Regex(@"\[([a-zA-Z0-9_\-]+)~=([^\]]+)\]", RegexOptions.Multiline),
                                              Replace = @"[contains(concat(' ',normalize-space(@$1),' '),concat(' ',$2,' '))]"
                                          },
                                          // ^= attrib
                                          new RegexReplace {
                                              Regex = new Regex(@"\[([a-zA-Z0-9_\-]+)\^=([^\]]+)\]", RegexOptions.Multiline),
                                              Replace = @"[starts-with(@$1,$2)]"
                                          },
                                          // != attrib
                                          new RegexReplace {
                                              Regex = new Regex(@"\[([a-zA-Z0-9_\-]+)\!=([^\]]+)\]", RegexOptions.Multiline),
                                              Replace = @"[not(@$1) or @$1!=$2]"
                                          },
                                          // ids
                                          new RegexReplace {
                                              Regex = new Regex(@"#([a-zA-Z0-9_\-]+)", RegexOptions.Multiline),
                                              Replace = @"[@id='$1']"
                                          },
                                          // classes
                                          new RegexReplace {
                                              Regex = new Regex(@"\.([a-zA-Z0-9_\-]+)", RegexOptions.Multiline),
                                              Replace = @"[contains(concat(' ',normalize-space(@class),' '),' $1 ')]"
                                          },
                                          // normalize multiple filters
                                          new RegexReplace {
                                              Regex = new Regex(@"\]\[([^\]]+)", RegexOptions.Multiline),
                                              Replace = @" and ($1)"
                                          },

                                      };
            #endregion

            foreach (var regexReplace in regexReplaces)
            {
                css = regexReplace.Regex.Replace(css, regexReplace.Replace);
            }

            return "//" + css;
        }
    }

    struct RegexReplace
    {
        public Regex Regex;
        public string Replace;
    }
}

And some tests

    [TestMethod]
    public void TestCssToXpathRules()
    {
        var translations = new Dictionary<string, string>
                               {
                                   { "*", "//*" }, 
                                   { "p", "//p" }, 
                                   { "p > *", "//p/*" }, 
                                   { "#foo", "//*[@id='foo']" }, 
                                   { "*[title]", "//*[@title]" }, 
                                   { ".bar", "//*[contains(concat(' ',normalize-space(@class),' '),' bar ')]" }, 
                                   { "div#test .note span:first-child", "//div[@id='test']//*[contains(concat(' ',normalize-space(@class),' '),' note ')]//*[1]/self::span" }
                               };

        foreach (var translation in translations)
        {
            var expected = translation.Value;
            var result = CssInliner.CssToXpath.Transform(translation.Key);

            Assert.AreEqual(expected, result);
        }
    }

    [TestMethod]
    public void HtmlWithMultiLineClassStyleReturnsInline()
    {
        #region var html = ...
        var html = XElement.Parse(@"<html>
                                        <head>
                                            <title>Hello, World Page!</title>
                                            <style>
                                                .redClass { 
                                                    background: red; 
                                                    color: purple; 
                                                }
                                            </style>
                                        </head>
                                        <body>
                                            <div class=""redClass"">Hello, World!</div>
                                        </body>
                                    </html>").ToString();
        #endregion

        #region const string expected ...
        var expected = XElement.Parse(@"<html>
                                            <head>
                                                <title>Hello, World Page!</title>
                                            </head>
                                            <body>
                                                <div class=""redClass"" style=""background: red; color: purple;"">Hello, World!</div>
                                            </body>
                                        </html>").ToString();
        #endregion

        var result = new CssInliner.CssInliner(html);

        Assert.AreEqual(expected, result.InlinedXhtml);
    }

There are more tests, but, they import html files for the input and expected output and I'm not posting all that!

But I should post the Normalize extension methods!

private static readonly Regex NormalizeSpaceRegex = new Regex(@"\s{2,}", RegexOptions.None);
public static string NormalizeSpace(this string data)
{
    return NormalizeSpaceRegex.Replace(data, @" ");
}

public static string NormalizeCharacter(this string data, char character)
{
    var normalizeCharacterRegex = new Regex(character + "{2,}", RegexOptions.None);
    return normalizeCharacterRegex.Replace(data, character.ToString());
}

解决方案

Since you're already 90% of the way there with your current implementation, why don't you use your existing framework but replace the XML parsing with an HTML parser instead? One of the more popular ones out there is the HTML Agility Pack. It supports XPath queries and even has a LINQ interface similar to the standard .NET interface provided for XML so it should be a fairly straightforward replacement.

这篇关于在C#中的内联CSS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆