简单的 CSS 解析器






4.79/5 (9投票s)
一个简单的 CSS 解析器,
引言
层叠样式表 (CSS) 允许开发人员为 Web 创建出色的用户界面。它们易于构建、使用和维护。当使用其内置的 HTML 到 PDF 功能时,iTextSharp 可以利用 CSS。要将样式表信息从 CSS 导入到 iTextSharp 中,开发人员需要读取 CSS 文件并将其转换为 Dictionary
,以便 iTextSharp 使用。本文将演示一个简单的解决方案,以执行该任务。包含的解决方案包括单元测试和一个 ASP.Net 项目,演示了如何使用 CSSParser
。
背景
在开发 HTML 到 PDF 实用程序时,我发现需要解析层叠样式表。互联网上有许多 CSS 解析器,但没有一个符合我的需求。我用 C# 创建了这个简单的基于正则表达式的 CSS 解析器,以促进在 iTextSharp 中生成 PDF。CSS 解析器的要求如下:
要求
- 读取 CSS 文件
- 将 CSS 存储在集合中
- 查询类及其属性
- 查询元素及其属性
- 易于维护和增强
- 轻松地将样式信息馈送到 iTextSharp 中,将 HTML 转换为 PDF
- 它应该精简
- 其他开发人员可以使用
使用代码
CSSParser 继承自一个泛型的 List
,其中包含 KeyValuePair
。键将是 CSS 选择器。值将是另一组键值对。这里的键是 CSS 属性名称。值将是 CSS 属性值。我使用了一个泛型的 List
而不是 Dictionary
,因为层叠样式表可以多次列出相同的选择器或属性。
public partial class CSSParser : List<KeyValuePair<String,List<KeyValuePair<String,String>>>>, ICSSParser
CSS 解析器的核心是一个正则表达式,我在 Stack Overflow 上找到 (http://stackoverflow.com/a/2694121/899290)。CSSGroups
正则表达式将获取样式表并将其分解为命名组。在解析 CSS 之前,将使用 CSSComments
正则表达式从文件中删除 CSS 注释。
public const String CSSGroups = @"(?<selector>(?:(?:[^,{]+),?)*?)\{(?:(?<name>[^}:]+):?(?<value>[^};]+);?)*?\}";
public const String CSSComments = @"(?<!"")\/\*.+?\*\/(?!"")";
private Regex rStyles = new Regex(CSSGroups, RegexOptions.IgnoreCase | RegexOptions.Compiled);
Read
方法负责解析样式表中的值并填充泛型 List
。它将使用 .Net Regex
类来删除任何注释并填充集合。
public void Read(String CascadingStyleSheet)
{
this.StyleSheet = CascadingStyleSheet;
if (!String.IsNullOrEmpty(CascadingStyleSheet))
{
//Remove comments before parsing the CSS. Don't want any comments in the collection.
MatchCollection MatchList = rStyles.Matches(Regex.Replace(CascadingStyleSheet,
RegularExpressionLibrary.CSSComments, String.Empty));
foreach (Match item in MatchList)
{
//Check for nulls
if (item != null && item.Groups != null &&
item.Groups[SelectorKey] != null &&
item.Groups[SelectorKey].Captures != null &&
item.Groups[SelectorKey].Captures[0] != null &&
!String.IsNullOrEmpty(item.Groups[SelectorKey].Value))
{
String strSelector = item.Groups[SelectorKey].Captures[0].Value.Trim();
var style = new List<KeyValuePair<String,String>>();
for (int i = 0; i < item.Groups[NameKey].Captures.Count; i++)
{
String className = item.Groups[NameKey].Captures[i].Value;
String value = item.Groups[ValueKey].Captures[i].Value;
//Check for null values in the properies
if (!String.IsNullOrEmpty(className) && !String.IsNullOrEmpty(value))
{
className = className.TrimWhiteSpace();
value = value.TrimWhiteSpace();
//One more check to be sure we are only pulling valid css values
if (!String.IsNullOrEmpty(className) && !String.IsNullOrEmpty(value))
{
style.Add(new KeyValuePair<String,String>(className, value));
}
}
}
this.Add(new KeyValuePair<String,List<KeyValuePair<String,String>>>(strSelector, style));
}
}
}
}
一旦列表填充完毕,使用 LINQ 或 Lambda 表达式来提取您需要的信息就变得很简单了。Classes
和 Elements
属性将样式表的值公开为 Dictionary
,可以将其提供给 iTextSharp。
public Dictionary<String, Dictionary<String,String>> Classes
{
get
{
if (classes == null || classes.Count == 0)
{
this.classes = this.Where(cl => cl.Key.StartsWith("."))
.ToDictionary(cl => cl.Key.Trim(new Char[] { '.' }), cl => cl.Value
.ToDictionary(p => p.Key, p => p.Value));
}
return classes;
}
}
public public Dictionary<String, Dictionary<String,String>> Elements
{
get
{
if (elements == null || elements.Count == 0)
{
elements = this.Where(el => !el.Key.StartsWith("."))
.ToDictionary(el => el.Key, el => el.Value
.ToDictionary(p => p.Key, p => p.Value));
}
return elements;
}
}
使用 CSS 解析器
CSSParser
为您提供了两个读取层叠样式表的选项,读取 CSS 文件或字符串。ReadCSSFile
方法将读取 CSS 文件并填充集合。您可以通过调用 Read
方法或将 CSS 值传递给构造函数来读取包含 CSS 信息的字符串。
void lnkParseCSSFile_Click(object sender, EventArgs e)
{
CSSParser parser = new CSSParser();
parser.ReadCSSFile(Server.MapPath("~/CSSParserStyle.css"));
//Display the Original CSS with some formating for the web
this.divOriginalCSS.InnerHtml = parser.StyleSheet.FixLineBreakForWeb().FixTabsForWeb().FixSpaceForWeb();
//Display the parsed CSS
this.divParsedCSS.InnerHtml = parser.ToString();
this.spnOriginalCSSLength.InnerText = parser.StyleSheet.Length.ToString();
this.spnParsedCSSLength.InnerText = this.divParsedCSS.InnerHtml.Length.ToString();
}
关注点
CSSParser
的 Elements
和 Classes
属性针对 iTextSharp 版本 5.x
历史
- 版本 1.0 - 初始发布