Chapter 36: DOM Node Info
XML DOM Node Information — written as if I am your patient teacher sitting next to you, drawing on the whiteboard, showing examples, explaining every property step by step, giving analogies, and providing code you can copy-paste and try immediately.
We will go slowly and clearly so you really understand:
- What information a node actually contains
- Which properties tell you what kind of node it is
- Which properties tell you where it is in the tree
- Which properties give you the actual content
- Which properties are read-only vs changeable
- Common confusion points and how to avoid them
1. First big picture – Every node has the same “ID card”
In the XML DOM, every node (element, text, attribute, comment, etc.) has a standard set of properties that describe:
- What kind of node it is
- What its name / value is
- Where it lives in the tree
- Who its neighbors are
- Whether it has children
These properties are the same for all node types — that is why you can write generic functions that walk the entire tree.
2. The most important node properties – with examples
We will use this small but realistic XML:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?xml version="1.0" encoding="UTF-8"?> <library> <!-- Popular books section --> <book id="B101" lang="en"> <title>Atomic Habits</title> <author>James Clear</author> <price currency="INR">499.00</price> </book> </library> |
Let’s load it and look at different nodes.
|
0 1 2 3 4 5 6 7 8 9 10 11 |
const xmlString = `... paste the XML above ...`; const parser = new DOMParser(); const xmlDoc = parser.parseFromString(xmlString, "application/xml"); const book = xmlDoc.querySelector("book"); |
Core identification properties
| Property | Type | What it tells you | Example for <book> element | Read-only? | Changeable? |
|---|---|---|---|---|---|
| nodeType | number | Which kind of node this is | 1 (Element) | Yes | No |
| nodeName | string | Tag name (for elements) or type name | “book” | Yes | No |
| nodeValue | string | The actual text (for text nodes) or null | null (for elements) | Yes | Yes (text nodes) |
| textContent | string | All text inside this node and descendants | “Atomic HabitsJames Clear499.00” | No | Yes |
| innerHTML | string | XML markup inside (not standard in pure XML) | Usually avoided in XML DOM | No | Yes (HTML DOM) |
Location & relationship properties
| Property | Type | What it tells you | Example for <price> node | Read-only? |
|---|---|---|---|---|
| parentNode | Node | Immediate parent node | The <book> element | Yes |
| parentElement | Element | Parent if it’s an element (more convenient) | <book> | Yes |
| childNodes | NodeList | All children (elements + text + comments) | Text nodes + <title>, <author>, <price> | Yes |
| children | HTMLCollection | Only element children (no text nodes) | <title>, <author>, <price> | Yes |
| firstChild | Node | First child (often a text node with whitespace) | Text node (newline) | Yes |
| firstElementChild | Element | First element child | <title> | Yes |
| lastChild | Node | Last child | Text node after <price> | Yes |
| lastElementChild | Element | Last element child | <price> | Yes |
| nextSibling | Node | Next node at same level | Next text node or element | Yes |
| nextElementSibling | Element | Next element sibling | Next <book> if any | Yes |
| previousSibling | Node | Previous node | Previous text node or element | Yes |
| previousElementSibling | Element | Previous element sibling | Previous <book> | Yes |
Content & attribute properties
| Property | Type | What it gives | Example |
|---|---|---|---|
| attributes | NamedNodeMap | All attributes as Attr nodes | { id: “B101”, lang: “en” } |
| hasAttributes() | boolean | Does this element have any attributes? | true for <book> |
| hasChildNodes() | boolean | Does it have any children? | true for <book> |
| textContent | string | All text inside + descendants (no markup) | “Atomic HabitsJames Clear499.00” |
| innerHTML | string | Markup inside (not reliable in pure XML DOM) | Avoid in XML |
| nodeValue | string / null | Text for text nodes, null for elements | “Atomic Habits” for <title> text node |
4. Practical code – Exploring a real node
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// Assume xmlDoc is already parsed const book = xmlDoc.querySelector("book"); console.group("Book node information"); console.log("nodeType:", book.nodeType); // 1 = Element console.log("nodeName:", book.nodeName); // "book" console.log("tagName:", book.tagName); // "book" (same as nodeName for elements) console.log("nodeValue:", book.nodeValue); // null (elements don't have nodeValue) console.log("textContent:", book.textContent.trim()); // All text inside console.log("Has attributes?", book.hasAttributes()); // true console.log("Attributes count:", book.attributes.length); // 2 console.log("id attribute:", book.getAttribute("id")); // "B101" console.log("Parent node:", book.parentNode.nodeName); // "library" console.log("First child:", book.firstChild.nodeType); // 3 = Text (whitespace) console.log("First element child:", book.firstElementChild.tagName); // "title" console.log("Children count (all nodes):", book.childNodes.length); console.log("Element children count:", book.children.length); // usually 3–4 console.groupEnd(); |
5. Very common real-world patterns when accessing nodes
Pattern 1 — Get all leaf elements and their values
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
const leaves = xmlDoc.querySelectorAll("book *"); // all children of books leaves.forEach(leaf => { if (leaf.nodeType === 1 && leaf.children.length === 0) { console.log(`${leaf.tagName}: ${leaf.textContent.trim()}`); } }); |
Pattern 2 — Skip whitespace text nodes
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function getElementChildrenOnly(parent) { const elements = []; for (let child of parent.childNodes) { if (child.nodeType === 1) { elements.push(child); } } return elements; } console.log(getElementChildrenOnly(book).map(el => el.tagName)); // ["title", "author", "price", "inStock"] |
Pattern 3 — Get all attributes as object
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function getAttributesAsObject(element) { const attrs = {}; for (let attr of element.attributes) { attrs[attr.name] = attr.value; } return attrs; } console.log(getAttributesAsObject(book)); // { id: "B101", lang: "en", category: "self-help" } |
6. Summary table – Quick reference for accessing nodes
| You want to know… | Property / Method | Returns | Notes / Tip |
|---|---|---|---|
| What kind of node is this? | nodeType | number (1,2,3,7,8,9…) | Memorize: 1=element, 3=text, 2=attribute |
| Tag name (for elements) | tagName or nodeName | string | Uppercase in HTML DOM, case-sensitive in XML |
| Text content (recursive) | textContent | string | Includes all descendant text + whitespace |
| Only direct text (if any) | nodeValue (on text node) | string | Usually use textContent |
| All attributes | attributes | NamedNodeMap | Like array but with named access |
| Specific attribute value | getAttribute(“currency”) | string or null | Returns null if missing |
| Parent element | parentElement | Element or null | More convenient than parentNode |
| First/last element child | firstElementChild / lastElementChild | Element or null | Skips text & comment nodes |
| Next/previous element sibling | nextElementSibling / previousElementSibling | Element or null | Skips text & comment nodes |
Would you like to continue with one of these topics?
- How to safely ignore whitespace text nodes
- Detailed tree walking (recursive functions, parent–child–sibling navigation)
- Creating, modifying, removing nodes with full examples
- Working with namespaces (very common in real XML data)
- Debugging tricks when node properties surprise you
- Real-world patterns (RSS parsing, SOAP response, configuration file…)
Just tell me which direction you want to explore next! 😊
