在CSQuery中选择遍历DOM的正确方法是什么?

时间:2014-05-09 02:49:39

标签: csquery

CSQuery是一个非常棒的C#库,可以帮助解析C#中的HTML。 https://github.com/jamietre/CsQuery

这是你对sizzler / jQuery所期待的所有善意,而且James Treworgy值得一些爱和钦佩。

为什么第二个选择第一个选择结果的结果是错误的元素数?

CQ fragment = CQ.CreateFragment(@"
<div>
    <ul>
        <li class=""number english"">one</li>
        <li class=""number english"">two</li>
        <li class=""number english"">three</li>
        <li class=""number english"">four</li>
        <li class=""number english"">five</li>
    </ul>
    <ul>
        <li class=""number spanish"">uno</li>
        <li class=""number spanish"">dos</li>
        <li class=""number spanish"">tres</li>
        <li class=""number spanish"">quatro</li>
        <li class=""number spanish"">cinco</li>
    </ul>
</div>
");

Assert.AreEqual(2, fragment["ul"].Length);
CQ english = fragment["ul:first"];
CQ spanish = fragment["ul:last"];
Assert.AreEqual(1, english.Length);
Assert.AreEqual(1, spanish.Length);

// english seems to not represent only the first ul, but the entire DOM
CQ englishNumbers = english["li.number"]; 
Assert.AreEqual(5, englishNumbers.Length); // Failed, expected <5> and was <10>

// Both of these methods work. I'm at a loss for as to why the first does not.
CQ spanishNumbers = spanish["li.number", spanish[0]]; // Give it context of where to start searching from
Assert.AreEqual(5, spanishNumbers.Length);

CQ spanishNumbers2 = spanish.Select("li.number", spanish.Elements);
Assert.AreEqual(5, spanishNumbers2.Length);

1 个答案:

答案 0 :(得分:1)

我一直在阅读源代码并撰写更多测试,并认为我已经弄明白了。

CsQuery/CQ_jQuery/Select.cspublic CQ Select(string selector, IDomObject context)public CQ Select(string selector)进行比较。 通过这种诗意的评论,这一切归结为public CQ Select(Selector selector)

// When running a true "Select" (which runs against the DOM, 
// versus methods that operate against the selection set) 
// we should use the CsQueryParent document, which is the DOM
// that sourced this.

我想要的魔法是使用此方法public Selector ToFilterSelector()CsQuery/Engine/Selector.cs

// Selecting from a resolved Select is the same as selecting from the root dom
CQ entireDomNumbers = fragment["li.number"];
CQ englishNumbers = english["li.number"];
Assert.AreEqual(entireDomNumbers.Length, englishNumbers.Length);

// When you want to select from a sub-part of the dom, explicitly use it as context
IEnumerable<IDomObject> spanishDomObjects = spanish;
CQ spanishNumbers = spanish["li.number", spanishDomObjects];
Assert.AreEqual(5, spanishNumbers.Length);

// Or from some specific part of the resolved CQ, again explicitly
IDomObject spanishDomObject = spanish[0];
CQ spanishNumbers2 = spanish["li.number", spanishDomObject];
Assert.AreEqual(5, spanishNumbers2.Length);

// Indexer [string, context] is same as Select(string, context) method
CQ spanishNumbers3 = spanish.Select("li.number", spanishDomObject);
Assert.AreEqual(5, spanishNumbers3.Length);

// Or in reverse from an IDomObject just for fun
CQ spanishNumbers3b = spanishDomObject.Cq().Select("li.number", spanish);
Assert.AreEqual(5, spanishNumbers3b.Length);

// Or from the collection...
CQ spanishNumbers4 = spanish.Select("li.number", spanishDomObjects);
Assert.AreEqual(5, spanishNumbers4.Length);

// in the end, Find was the droid I was looking for
CQ findSpanishNumbers = spanish.Find("li.number");
Assert.AreEqual(5, findSpanishNumbers.Length);