1

Is it possible to run just a single query to replace multiple queries?

 //host_info[hostname="localhost" and vulnerability_id="remote_execution"][1]
 //host_info[hostname="localhost" and vulnerability_id="remote_execution"][1]/@exclude
 //host_info[hostname="localhost" and vulnerability_id="remote_execution"][1]/../problem[1]
 //host_info[hostname="localhost" and vulnerability_id="remote_execution"][1]/../reference[1]
 //host_info[hostname="localhost" and vulnerability_id="remote_execution"][1]/../impact[1]
 //host_info[hostname="localhost" and vulnerability_id="remote_execution"][1]/../background[1]
 //host_info[hostname="localhost" and vulnerability_id="remote_execution"][1]/../resolution[1]

For some reason this doesn't work in PHP's xpath() function.

//host_info[hostname="localhost" and vulnerability_id="remote_execution"]/(*, ../background, ../impact, ../problem)

I feel there has to be a better way here. Please note it's possible to have multiple <host_info> nodes which is why I'm targeting the hostname and vulnerability_id. But there are only one <background>, <resolution> nodes contained in the parent <vulnerability_id> node.

<report>
<vulnerability>
   <host_info>
      <hostname></hostname>
      <vulnerability_id></vulnerability_id>
   </host_info>
   <host_info>
      <hostname></hostname>
      <vulnerability_id></vulnerability_id>
   </host_info>
   <background></background>
   <resolution></resolution>
</vulnerability>
<vulnerability>
   <host_info></host_info>
   <host_info></host_info>
   <host_info></host_info>
   <host_info></host_info>
   <background></background>
   <resolution></resolution>
</vulnerability>
</report>

1 Answer 1

1

A node list has only a single dimension, so it is not really useful to serialize details of multiple items into a single list.

Typically you would use one Xpath expression to identify your list nodes and then DOM methods and relative expressions to fetch data related to these nodes:

$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMxpath($document);

foreach ($xpath->evaluate('//host_info[hostname="localhost" and vulnerability_id="remote_execution"]') as $hostInfo) {
    var_dump(
      [
          $hostInfo->getAttribute('exclude'),
          $xpath->evaluate('string(parent::*/background)', $hostInfo),
          $xpath->evaluate('string(parent::*/resolution)', $hostInfo)
        ]
    );
}

For a single item it is possible to fetch all the detail nodes into a single result list. However an expression like that will get complex fast and you then have to add logic that recognizes the different detail nodes.

$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMxpath($document);

$expression = <<<'XPATH'
//host_info[hostname="localhost" and vulnerability_id="remote_execution"][1]/@exclude|
(//host_info[hostname="localhost" and vulnerability_id="remote_execution"][1]/parent::*/background)[1]|
(//host_info[hostname="localhost" and vulnerability_id="remote_execution"][1]/parent::*/resolution)[1]
XPATH;

foreach ($xpath->evaluate($expression) as $detail) {
    var_dump(
       $detail->localName, $detail->textContent
    );
} 
Sign up to request clarification or add additional context in comments.

1 Comment

Great explanation. Thanks!!! This has cleaned up a bunch of code and made things about 4x faster. You're right things can get complex really quick. Thanks again.

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.