0
# Query & Selection
1
2
Powerful element querying capabilities using CSS selectors, tag names, IDs, and DOM traversal methods for finding and navigating HTML elements within the parsed DOM tree.
3
4
## Capabilities
5
6
### CSS Selector Queries
7
8
Query elements using standard CSS selector syntax with support for classes, IDs, attributes, and combinators.
9
10
```typescript { .api }
11
/** Find first element matching CSS selector */
12
querySelector(selector: string): HTMLElement | null;
13
14
/** Find all elements matching CSS selector */
15
querySelectorAll(selector: string): HTMLElement[];
16
```
17
18
**Supported CSS Selectors:**
19
20
- **Type selectors**: `div`, `p`, `span`
21
- **Class selectors**: `.class-name`, `.multiple.classes`
22
- **ID selectors**: `#element-id`
23
- **Attribute selectors**: `[attr]`, `[attr=value]`, `[attr*=value]`
24
- **Descendant combinators**: `div p`, `.parent .child`
25
- **Child combinators**: `div > p`
26
- **Adjacent sibling**: `h1 + p`
27
- **Pseudo-selectors**: `:first-child`, `:last-child`, `:nth-child()`
28
29
**Usage Examples:**
30
31
```typescript
32
import { parse } from "node-html-parser";
33
34
const html = `
35
<div class="container">
36
<header id="main-header">
37
<h1>Title</h1>
38
<nav class="menu">
39
<ul>
40
<li><a href="/home">Home</a></li>
41
<li><a href="/about" class="active">About</a></li>
42
</ul>
43
</nav>
44
</header>
45
<main>
46
<p class="intro">Introduction text</p>
47
<article data-id="123">
48
<h2>Article Title</h2>
49
<p>Article content</p>
50
</article>
51
</main>
52
</div>`;
53
54
const root = parse(html);
55
56
// Basic selectors
57
const header = root.querySelector('#main-header');
58
const intro = root.querySelector('.intro');
59
const articles = root.querySelectorAll('article');
60
61
// Compound selectors
62
const activeLink = root.querySelector('a.active');
63
const navLinks = root.querySelectorAll('nav a');
64
65
// Attribute selectors
66
const dataElement = root.querySelector('[data-id]');
67
const specificData = root.querySelector('[data-id="123"]');
68
69
// Descendant selectors
70
const headerTitle = root.querySelector('header h1');
71
const listItems = root.querySelectorAll('ul li');
72
73
// Child selectors
74
const directChildren = root.querySelectorAll('.container > header');
75
76
// Multiple results
77
const allParagraphs = root.querySelectorAll('p');
78
allParagraphs.forEach(p => console.log(p.text));
79
```
80
81
### Element Queries by Tag
82
83
Find elements by their HTML tag name with wildcard support.
84
85
```typescript { .api }
86
/**
87
* Find all elements with specified tag name
88
* @param tagName - Tag name to search for, or '*' for all elements
89
* @returns Array of matching HTMLElements
90
*/
91
getElementsByTagName(tagName: string): HTMLElement[];
92
```
93
94
**Usage Examples:**
95
96
```typescript
97
const root = parse(`
98
<div>
99
<p>First paragraph</p>
100
<span>Span content</span>
101
<p>Second paragraph</p>
102
</div>
103
`);
104
105
// Find by specific tag
106
const paragraphs = root.getElementsByTagName('p');
107
console.log(paragraphs.length); // 2
108
109
// Find all elements
110
const allElements = root.getElementsByTagName('*');
111
console.log(allElements.length); // 4 (div, p, span, p)
112
113
// Case insensitive
114
const divs = root.getElementsByTagName('DIV');
115
console.log(divs.length); // 1
116
```
117
118
### Element Query by ID
119
120
Find a single element by its ID attribute.
121
122
```typescript { .api }
123
/**
124
* Find element with specified ID
125
* @param id - ID value to search for
126
* @returns HTMLElement with matching ID, or null if not found
127
*/
128
getElementById(id: string): HTMLElement | null;
129
```
130
131
**Usage Examples:**
132
133
```typescript
134
const root = parse(`
135
<div>
136
<header id="main-header">Header</header>
137
<section id="content">
138
<p id="intro">Introduction</p>
139
</section>
140
</div>
141
`);
142
143
const header = root.getElementById('main-header');
144
const intro = root.getElementById('intro');
145
const missing = root.getElementById('not-found'); // null
146
147
console.log(header?.tagName); // "HEADER"
148
console.log(intro?.text); // "Introduction"
149
```
150
151
### Ancestor Traversal
152
153
Find the closest ancestor element matching a CSS selector.
154
155
```typescript { .api }
156
/**
157
* Traverse up the DOM tree to find closest ancestor matching selector
158
* @param selector - CSS selector to match against ancestors
159
* @returns Closest matching ancestor HTMLElement, or null if none found
160
*/
161
closest(selector: string): HTMLElement | null;
162
```
163
164
**Usage Examples:**
165
166
```typescript
167
const root = parse(`
168
<article class="post">
169
<header>
170
<h1>Title</h1>
171
</header>
172
<div class="content">
173
<p>
174
<em id="emphasis">emphasized text</em>
175
</p>
176
</div>
177
</article>
178
`);
179
180
const emphasis = root.getElementById('emphasis');
181
182
// Find closest paragraph
183
const paragraph = emphasis.closest('p');
184
console.log(paragraph?.tagName); // "P"
185
186
// Find closest article
187
const article = emphasis.closest('article');
188
console.log(article?.classList.contains('post')); // true
189
190
// Find closest with class
191
const content = emphasis.closest('.content');
192
console.log(content?.tagName); // "DIV"
193
194
// No match
195
const missing = emphasis.closest('table'); // null
196
```
197
198
## Advanced Query Patterns
199
200
### Chaining Queries
201
202
Combine multiple query methods for complex element finding:
203
204
```typescript
205
const root = parse(`
206
<div class="app">
207
<nav class="sidebar">
208
<ul class="menu">
209
<li><a href="/dashboard" class="active">Dashboard</a></li>
210
<li><a href="/settings">Settings</a></li>
211
</ul>
212
</nav>
213
</div>
214
`);
215
216
// Chain queries
217
const activeLink = root
218
.querySelector('.sidebar')
219
?.querySelector('.menu')
220
?.querySelector('a.active');
221
222
console.log(activeLink?.text); // "Dashboard"
223
224
// Alternative approach
225
const menu = root.querySelector('.menu');
226
const activeItem = menu?.querySelector('.active');
227
```
228
229
### Iterating Query Results
230
231
Work with multiple elements returned by queries:
232
233
```typescript
234
const root = parse(`
235
<table>
236
<tr><td>Name</td><td>Age</td></tr>
237
<tr><td>Alice</td><td>25</td></tr>
238
<tr><td>Bob</td><td>30</td></tr>
239
</table>
240
`);
241
242
// Process all rows
243
const rows = root.querySelectorAll('tr');
244
rows.forEach((row, index) => {
245
const cells = row.querySelectorAll('td');
246
console.log(`Row ${index}:`, cells.map(cell => cell.text));
247
});
248
249
// Filter results
250
const dataCells = root.querySelectorAll('td');
251
const ages = dataCells
252
.filter(cell => !isNaN(Number(cell.text)))
253
.map(cell => Number(cell.text));
254
255
console.log('Ages:', ages); // [25, 30]
256
```
257
258
### Conditional Queries
259
260
Handle cases where elements might not exist:
261
262
```typescript
263
const root = parse('<div><p>Content</p></div>');
264
265
// Safe querying with optional chaining
266
const text = root.querySelector('section')?.querySelector('p')?.text ?? 'Default';
267
268
// Explicit null checks
269
const section = root.querySelector('section');
270
if (section) {
271
const paragraph = section.querySelector('p');
272
if (paragraph) {
273
console.log(paragraph.text);
274
}
275
}
276
277
// Using || for defaults
278
const title = root.querySelector('h1')?.text || 'No title found';
279
```
280
281
### Query Performance Tips
282
283
- **Specific selectors**: Use IDs and specific classes when possible
284
- **Limit scope**: Query from specific parent elements rather than root
285
- **Cache results**: Store frequently accessed elements in variables
286
- **Batch operations**: Collect all needed elements before processing
287
288
```typescript
289
// Good: Specific and scoped
290
const sidebar = root.getElementById('sidebar');
291
const menuItems = sidebar?.querySelectorAll('li') ?? [];
292
293
// Less optimal: Broad queries
294
const allItems = root.querySelectorAll('li'); // Searches entire document
295
296
// Cache frequently used elements
297
const header = root.querySelector('header');
298
if (header) {
299
const nav = header.querySelector('nav');
300
const logo = header.querySelector('.logo');
301
// Use cached elements for multiple operations
302
}
303
```