0

I'm using an XPath query to find attribute values. However, I want to go through each div and if the attributes are not found, return nothing. Is there a way to do this?

HTML:

<div id="a" class="a">text</div>
<div>text</div>
<div id="b" class="b">text</div>

XPath:

$values = $XPath->query('//div/@id | //div/@class');

Result:

array('a', 'a', 'b', 'b');

Desired Result:

array('a', 'a', '', '', 'b', 'b');

As of now, I'm kind of in XPath already, and I would like to stay in this direction for right now.

2 Answers 2

3

Why not just selecting all <div> elements and the use DOMElement::getAttribute() to obtain the attibute values? Note that this method will return an empty string if the current element didn't has the attribute which is requested. (What should actually what you want).

Try this:

$html = <<<EOF
<div id="a" class="a"></div>
<div></div>
<div id="b" class="b"></div>
EOF;

$doc = new DOMDocument();
$doc->loadHtml($html);
$selector = new DOMXpath($doc);

$result = array();
foreach($selector->query('//div') as $div) {
    $result []= $div->getAttribute('id');
    $result []= $div->getAttribute('class');
}

var_dump($result);

Output:

array(6) {
  [0] =>
  string(1) "a"
  [1] =>
  string(1) "a"
  [2] =>
  string(0) ""
  [3] =>
  string(0) ""
  [4] =>
  string(1) "b"
  [5] =>
  string(1) "b"
}
Sign up to request clarification or add additional context in comments.

7 Comments

this looks good, I upvoted, sorry my internet is crap right now, pages take 5 min to load...
reading stackoverflow is at least better than watching youtube vids in this case ;)
haha, it's not that bad I guess. thanks for this answer, it was much more clever than what I was thinking.
Note that it is many cases clever do let only XPath do the work. It is very powerful and you can do cool things with it. But in this case this solution looks best (for me). If I'll find a xpath-only solution (I think there is one) I'll add it to my answer
There is no xpath soution because nodes in a nodeset that get returned are in document order (or reverse document order depending on the axis), as the NULL values (or empty strings) are not from a node, they a) can not be queried - but even if they could - b) are not in that document order because not part of the document. You would need to insert those attributes first before querying again. Likely not what is wanted.
|
2

I just add an additional answer to provide my own wording and that you can easily see that what @hek2gml suggest is sensible.

An xpath query can only return what is in the document already. So you can not insert non-existing nodes in the same query.

So you need to do it like your describe what you want to do:

I want to go through each div and if the attributes are not found, return nothing.

So per each match of a div, get both attribute values, empty attribute values incl.:

$html = <<<BUFFER
<div id="a" class="a">text</div>
<div>text</div>
<div id="b" class="b">text</div>
BUFFER;

$xml = simplexml_import_dom(@DOMDocument::loadHTML($html));

$divs = $xml->xpath('/*/body/div');

$reduce = function(array $array, SimpleXMLElement $div) {
    $array[] = (string) $div['id'];
    $array[] = (string) $div['class'];
    return $array;
};

$values = array_reduce($divs, $reduce, []);

print_r($values);

The output is as expected:

Array
(
    [0] => a
    [1] => a
    [2] => 
    [3] => 
    [4] => b
    [5] => b
)

1 Comment

that is too advanced for me lol! upvoted though, I really appreciate the time you spent :D

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.