Free tools Windows power users keep installed
One-click scans. No signup required.
Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Use nextSibling or previousSibling to move through a DOM node’s parent’s child list. Because that list includes text and comment nodes as well as elements, loop until you reach an element—or use XPath’s following-sibling::*[1] or preceding-sibling::*[1] when you need the nearest sibling element.
What counts as a sibling in PHP’s DOM?
The PHP DOM extension represents an HTML document as a tree. Two nodes are siblings only when they have the same parent. Their order in that parent’s child list determines which one comes before or after the other. A node inside a nested element is not a sibling of nodes outside that element, even if they appear next to each other in the source markup.
In PHP’s DOM API, nextSibling and previousSibling refer to the adjacent node in that child list. They do not mean “next HTML element” and “previous HTML element.” The adjacent node may be an element, text, or comment, and either property can be null at the relevant end of the list.
The practical choice is straightforward: use a filtered loop when you are already holding a node and want to move from it; use XPath when you want to find a node by conditions and select a sibling in the same query.
#1 Best Overall
Get the next sibling element with DOMDocument
This complete example loads a small HTML fragment, finds the second list item, and walks forward until it finds the next element. It skips the indentation and newline text nodes between the <li> elements.
<?php
$html = <<<'HTML'
<ul>
<li class="first">One</li>
<li class="target">Two</li>
<li class="third">Three</li>
</ul>
HTML;
$doc = new DOMDocument();
libxml_use_internal_errors(true);
$doc->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
libxml_clear_errors();
$target = $doc->getElementsByTagName('li')->item(1);
$nextElement = null;
if ($target !== null) {
for ($node = $target->nextSibling; $node !== null; $node = $node->nextSibling) {
if ($node->nodeType === XML_ELEMENT_NODE) {
$nextElement = $node;
break;
}
}
}
echo $nextElement ? $nextElement->textContent : 'No next element';
// Three
?>
getElementsByTagName('li')->item(1) selects the second list item because the collection is zero-indexed. The null check matters: the collection may not contain a second item. The loop starts with the immediately adjacent node, then advances across the same parent’s child list. It stops at the first element; if no later element exists, $nextElement remains null.
The element test uses XML_ELEMENT_NODE, so it does not mistake whitespace or a comment for an HTML element. An equivalent object-oriented test is $node instanceof DOMElement. Checking the node type is useful when the goal is specifically to select elements and the rest of the code can work with DOM nodes.
Rank #2
Find the previous sibling element
For the nearest previous element, use the same pattern while following previousSibling backward:
$previousElement = null;
if ($target !== null) {
for ($node = $target->previousSibling; $node !== null; $node = $node->previousSibling) {
if ($node->nodeType === XML_ELEMENT_NODE) {
$previousElement = $node;
break;
}
}
}
echo $previousElement ? $previousElement->textContent : 'No previous element';
Since the loop begins with the immediately preceding node and breaks on the first element, the result is the closest previous element—not the first element in document order. If the starting node is the first element child, the loop may encounter only whitespace or comments before it reaches the parent boundary, and then return no element.
Use XPath for a concise sibling query
DOMXPath is useful when the starting node is identified by a tag, attribute, or other query condition. The wildcard in following-sibling::* or preceding-sibling::* selects elements, so whitespace text nodes and comments are excluded.
$xpath = new DOMXPath($doc);
$next = $xpath->query(
"//li[@class='target']/following-sibling::*[1]"
)->item(0);
$previous = $xpath->query(
"//li[@class='target']/preceding-sibling::*[1]"
)->item(0);
echo $next ? $next->textContent : 'No next element';
echo $previous ? $previous->textContent : 'No previous element';
following-sibling::*[1] selects the nearest following element sibling of any tag. preceding-sibling::*[1] selects the nearest preceding element sibling. Both queries return a DOMNodeList; calling item(0) gives the first result or null if there is none.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsChange the node test to narrow the matches. For example, following-sibling::div selects all later div element siblings, not just the nearest one. preceding-sibling::p[1] selects the closest preceding p on XPath’s reverse axis. Add predicates when you need a sibling matching an attribute or other condition.
XPath 1.0 queries operate on the document tree; they are not CSS selectors. In particular, the sibling axes only examine nodes sharing the context node’s parent. If your desired element is nested in another container, first select that nested element or adjust the query path to the actual context.
Rank #4
Choose a loop or XPath
| Need | Use | Why |
|---|---|---|
| You already have the target node and need the closest next or previous element. | A sibling loop filtered by nodeType. |
The traversal is explicit and handles intervening text and comment nodes. |
| You need a sibling based on a tag, class, or other query condition. | DOMXPath. |
The location and sibling condition can be expressed in one query. |
| You want every later sibling matching a particular element name. | An XPath sibling axis such as following-sibling::div. |
The query returns all later matching element siblings, not just the nearest one. |
Use the loop when clarity about traversal and node filtering matters most. Use XPath when combining selection conditions would otherwise require several separate steps.
Why does nextSibling return whitespace?
In formatted HTML such as a list with each item on its own indented line, the newline and spaces between tags are represented as text nodes. Those nodes are part of the parent’s child list, so $target->nextSibling can be a whitespace text node rather than the next <li>. Comments between elements can be returned in the same way.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Do not read $target->nextSibling->textContent on the assumption that the result is an element. Iterate until nodeType === XML_ELEMENT_NODE, or run an XPath query using following-sibling::*[1]. The latter’s element wildcard is the key: a query for following-sibling::node()[1] can select a text or comment node instead.
Load HTML safely enough for the task
The examples use the established global DOMDocument and DOMXPath classes. The PHP DOM extension provides operations on XML and HTML documents through the DOM API. Make sure the extension is available in the PHP runtime that executes the script.
DOMDocument::loadHTML() parses HTML into a tree, which may be repaired or normalized when the input is malformed. If your source has encoding issues, normalize or declare its encoding appropriately before relying on text content or exact tree structure. The sample suppresses parser warnings locally with libxml_use_internal_errors(true) and clears accumulated errors afterwards. For applications that need diagnostics, inspect libxml errors before clearing them instead of silently discarding them.
LIBXML_HTML_NOIMPLIED and LIBXML_HTML_NODEFDTD are used here to avoid adding implied HTML and doctype nodes around a fragment. If you are processing a full document or require a particular document structure, choose parsing options to suit that input; sibling relationships are determined by the tree that the parser actually creates.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →PHP version and DOM class choices
The global DOMDocument and DOMXPath classes remain the compatibility baseline for existing code. PHP 8.4 adds the namespaced, spec-compliant DomDocument family; its inherited nextSibling and previousSibling properties express the same tree relationship. Use the class family supported by your deployment and dependencies. The examples above use the global classes so they fit the established API.
Troubleshoot common sibling-query failures
- The result is whitespace or a comment: the property returns the adjacent node, not necessarily an element. Filter by
XML_ELEMENT_NODEor use the XPath element wildcard. - The result is
null: the target may be at the end or beginning of its parent’s child list, there may be no matching sibling, or the initial query may not have found the target. Check the target before traversal and handle an absent result before accessing properties. - The selected node is in the wrong part of the page: the sought node may be a descendant or belong to a different parent. Sibling axes do not cross parent boundaries. Verify the target’s parent and the parsed nesting.
- An XPath query returns no result: confirm the element and attribute condition match the parsed document, and that the context is the node you intend. A sibling query cannot find a node nested under another sibling.
- Text or nesting differs from the source HTML: HTML parsing may repair malformed markup, and encoding mismatches can affect text. Check the parsed tree and address input encoding before changing the sibling logic.
- Parser warnings appear: malformed or fragment HTML can produce libxml warnings. Internal-error mode lets a script manage them; inspect errors when diagnosing input rather than assuming the parser produced the intended tree.
Or skip the browser setup
For a separate task—capturing a webpage as an image or PDF—ScreenshotNeo is a website screenshot API and MCP server, not a replacement for DOM sibling traversal. A single GET request can return a screenshot; the cURL example below saves a WebP image. See the ScreenshotNeo documentation for request options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo accepts cookie or consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots.
Sign up free for 1,000 screenshots a month—no card required.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

