What is the correct way to traverse the DOM presented by a Select in CSQuery?

StackOverflow https://stackoverflow.com/questions/23555849

  •  18-07-2023
  •  | 
  •  

문제

CSQuery is an awesome C# library that helps with the parsing of HTML in C#. https://github.com/jamietre/CsQuery

It's all the goodness you'd expect from sizzler/jQuery, and James Treworgy deserves some love and admiration.

Why does the second Select from the result of a first Select result in the wrong number of elements?

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);
도움이 되었습니까?

해결책

I've been reading the source and writing more tests and think I have this figured out.

CsQuery/CQ_jQuery/Select.cs compare public CQ Select(string selector, IDomObject context) to public CQ Select(string selector). It all boils down to public CQ Select(Selector selector) with this poetic comment.

// 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.

The magic I want is when this method public Selector ToFilterSelector() is used. 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);
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top