繁体   English   中英

使用 HtmlAgilityPack 向 Html 添加样式属性的更好方法

[英]Better way to add a style attribute to Html using HtmlAgilityPack

我正在使用 HtmlAgilityPack。 我正在搜索所有 P 标签并在 P 标签内的样式中添加“margin-top:0px”。

如您所见,这有点“强制”margin-top 属性。 似乎必须有更好的方法来使用 HtmlAgilityPack 但我找不到它,而且 HtmlAgilityPack 文档不存在。

有人知道更好的方法吗?

HtmlNodeCollection pTagNodes = node.SelectNodes("//p[not(contains(@style,'margin-top'))]");

if (pTagNodes != null && pTagNodes.Any())
{
    foreach (HtmlNode pTagNode in pTagNodes)
    {
        if (pTagNode.Attributes.Contains("style"))
        {
            string styles = pTagNode.Attributes["style"].Value;
            pTagNode.SetAttributeValue("style", styles + "; margin-top: 0px");
        }
        else
        {
            pTagNode.Attributes.Add("style", "margin-top: 0px");
        }
    }
}


更新:我已经根据 Alex 的建议修改了代码。 仍然想知道 HtmlAgilityPack 中是否有一些内置功能可以以更“DOM”的方式处理样式属性。

const string margin = "; margin-top: 0px";

HtmlNodeCollection pTagNodes = node.SelectNodes("//p[not(contains(@style,'margin-top'))]");

if (pTagNodes != null && pTagNodes.Any())
{
    foreach (var pTagNode in pTagNodes)
    {
        string styles = pTagNode.GetAttributeValue("style", "");
        pTagNode.SetAttributeValue("style", styles + margin);
    }
}

您可以使用HtmlNode.GetAttributeValue方法稍微简化您的代码,并使您的“margin-top”魔术字符串保持不变:

const string margin = "margin-top: 0";
foreach (var pTagNode in pTagNodes)
{
    var styles = pTagNode.GetAttributeValue("style", null);
    var separator = (styles == null ? null : "; ");
    pTagNode.SetAttributeValue("style", styles + separator + margin);
}

这不是一个非常显着的改进,但这个代码对我来说更简单。

首先,你确定你需要的不仅仅是你要求的吗? 亚力克斯解决方案应该能够很好地解决您当前的问题,如果它总是那么“简单”,为什么要麻烦并增加它的复杂性呢?

不管怎样,AgilityPack没有那种功能,但是.Net Framework肯定有。 请注意,这只适用于.Net 4,如果您使用的是早期版本,则可能会有所不同。 首先,System.Web.dll附带了CssStyleCollection Class ,这个类已经包含了你想要解析内联css的所有内容,只有一个catch,它的构造函数是内部的,所以解决方案有点“hacky”。 首先,为了构建一个类的实例,你需要的只是一些反思,代码已经在这里完成 请记住,这现在可以正常工作,但可能会在.Net的未来版本中出现问题。 剩下的就是这么简单

CssStyleCollection css = CssStyleTools.Create();
css.Value = "border-top:1px dotted #BBB;margin-top: 0px;font-size:12px";
Console.WriteLine(css["margin-top"]); //prints "0px"

如果由于某种原因你不能添加对System.Web的引用(如果你使用.Net 4 Client Profile就是这种情况),总是有可能使用Reflector。

就个人而言,我会选择亚历克斯的解决方案,但这取决于你的决定。 :)

只需使用HtmlNode的以下扩展方法:

public static void AddOrUpdateCssValue(this HtmlNode htmlNode, string cssKey, string cssValue)
{
    string style = htmlNode.GetAttributeValue("style", "");
    string newStyle = addOrUpdateCssStyleKeyValue(style: style, newKey: cssKey, newValue: cssValue);

    htmlNode.SetAttributeValue(name: "style", value: newStyle);
}
private static string addOrUpdateCssStyleKeyValue(string style, string newKey, string newValue)
{
    if (String.IsNullOrEmpty(style)) return style;
    if (String.IsNullOrEmpty(newKey)) return style;
    if (String.IsNullOrEmpty(newValue)) return style;

    style = style.Clone() as string;
    List<string> keyValue = style.Split(';').Where(x => String.IsNullOrEmpty(x) == false).Select(x => x.Trim()).ToList();

    bool found = false;
    List<string> updatedStyles = new List<string>();
    foreach (string keyValuePair in keyValue)
    {
        if (String.IsNullOrEmpty(keyValuePair) == true) continue;
        if (keyValuePair.Contains(':') == false) continue;

        List<string> splitted = keyValuePair.Split(':').Where(x => String.IsNullOrEmpty(x) == false).Select(x => x.Trim()).ToList();
        if (splitted == null) continue;
        if (splitted.Count < 2) continue;

        string key = splitted[0];
        string value = splitted[1];

        if (key == newKey)
        {
            value = newValue;
            found = true;
        }

        updatedStyles.Add(String.Format("{0}: {1}", key, value));
    }

    if (found == false)
    {
        updatedStyles.Add(String.Format("{0}: {1}", newKey, newValue));
    }

    string result = String.Join("; ", updatedStyles);
    return result;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM