sschmeck
sschmeck

Reputation: 7675

Apply selector on sub elements with cheerio

I've found no way for applying selectors on cheerio elements (version 1.0.0-rc.3). Using find() raises an error.

const xmlText = `
<table>
  <tr><td>Foo</td><td/></tr>
  <tr><td>1,2,3</td><td>number</td></tr>
  <tr><td>A,B</td><td>char</td></tr>
  <!-- more rows -->
</table>
<table>
  <tr><td>Bar</td><td/></tr>
  <!-- more rows -->
</table>
`
const $ = cheerio.load(xmlText)
$('table').each((i, table) => {
  // TODO if first row contains Foo then map the following rows
  if (table.find("td:contains('Foo')").length > 0) {
    // ...
  }
})

Property 'find' does not exist on type 'CheerioElement'.

How can I apply selectors of sub elements?

The given example should only process table with first row text Foo and return the following list of objects.

// desired result
[{ value: '1,2,3', type: 'numbner' }, { value: 'A,B', type: 'char' }, ...]

Upvotes: 0

Views: 318

Answers (2)

sschmeck
sschmeck

Reputation: 7675

I found the answer in the documentation of each() method. You have to wrap the given element like $(element).

if ($(table).find("td:contains('Foo')").length > 0) {

Finally I solved the problem.

const $ = cheerio.load(xmlText)
const isFooTable = (i: number, e: CheerioElement) =>
  $('td', e).first().text() === 'Foo'
const result: { value: string; type: string }[] = []

$('table')
  .filter(isFooTable)
  .find('tr')
  .slice(1)
  .each((_, tr) => {
    const tds = $(tr).find('td')
    result.push({
      value: tds.first().text(),
      type: tds.last().text(),
    })
  })

Upvotes: 1

Darek Adamkiewicz
Darek Adamkiewicz

Reputation: 453

Written from scratch, I'm sure there's a better way to do this:

$('table').each((i, table) => { if ($(table).find("td:contains('Foo')").length > 0) {$('tr', table).each((i, tr)=>{console.log($(tr).text())})} })

Upvotes: 1

Related Questions