111,098
社区成员




<html>
<head>
<title>js</title>
<style>
/*
> 1 子
~ 2 通用
+ 3 相邻
*/
.a>.b {font-style:italic;}
</style>
</head>
<body>
<div class="a">
<div class="b">1</div>
<div class="b"><span class="d">2</span></div>
<div class="b">3</div>
<div class="b">4</div>
<b isConvert="true">
<div class="b">5</div>
</b>
<i isConvert="true">
<b isConvert="true">
<div class="b">55</div>
</b>
</i>
<i>
<b isConvert="true">
<div class="b">555</div>
</b>
</i>
<span class="c">
<div class="b">6</div>
<div class="b">7</div>
<div class="b">8</div>
<div class="b">9</div>
<div class="b">10</div>
</span>
</div>
</body>
XmlNodeList xnl1 = xml.SelectNodes("//*[contains(@class,'a')]/*[contains(@class,'b')]");
XmlNodeList xnl1 = xml.SelectNodes("//*[contains(@class,'a')]/*[contains(@class,'b')]");
XmlNodeList xnl2 = xml.SelectNodes("//*[contains(@class,'a')]/*[@isConvert]/*[contains(@class,'b')]");
XmlNodeList xnl3 = xml.SelectNodes("//*[contains(@class,'a')]/*[@isConvert]/*[@isConvert]/*[contains(@class,'b')]");
xml.SelectNodes("//*[@class='a']/*[@class='b']|//*[@class='a']/*[@isConvert='true']//*[@class='b' and parent::*[@isConvert='true']]")
测试通过,用Linq的All判断isConvert='true'
不过,这仅是针对你给出的文本通过,对于多级节点/*[@isConvert='true']//*[@class='b'
会有bug,对下面的节点也会匹配到,因为只判断了55父节点b,却忽略了span
<i isConvert="true">
<span><b isConvert="true">
<div class="b">55</div>
</b></span>
下面这样可以,最好写成递归的方式
var xml = XDocument.Parse(html);
Func<XElement, bool> childFilter = e => e.Attribute("class") != null && e.Attribute("class").Value == "b";
Func<XElement, bool> descendants = e => e.DescendantsAndSelf().Any(d => childFilter(d)
&& d.Ancestors().All(a => a.Attribute("isConvert") != null && a.Attribute("isConvert").Value == "true"));
var root = xml.Elements().First();
root.SetAttributeValue("isConvert", "true"); //加这个是为了保证d.Ancestors().All反向匹配所有父节点
foreach (var node in root.Elements().Where(e => childFilter(e) || descendants(e)))
Console.WriteLine(node.Value);