3v4l.org

run code in 300+ PHP versions simultaneously
<?php // Define a test HTML document containing two tables. Note that the first table // has a row that combined <th> and <td> cells, while the second one only has // <th> cells. $xhtml = <<<XHTML <html> <head> <title>Table test page</title> </head> <body> <table> <tr> <th>Cell 1</th> <td>Cell 2</td> </tr> </table> <table> <tr> <th>Cell 1</th> <th>Cell 2</th> </tr> </table> </body> </html> XHTML; $document = new DOMDocument(); $document->loadXML($xhtml); $xpath = new DOMXPath($document); $xpath = function ($query) use ($xpath) { echo $query . "\n"; $result = $xpath->query($query); if (method_exists($result, 'count')) { $count = $result->count(); } else { // Fallback for older PHP versions that don't have DomNodeList::count(). $result_array = iterator_to_array($result); // Filter out any bogus results that equal `NULL`. $result_array = array_filter($result_array); $count = count($result_array); } echo $count . ' result' . ($count != 1 ? 's' : '') . ($count ? ':' : '') . "\n"; foreach ($result as $element) { $document = new DOMDocument(); $document->appendChild($document->importNode($element->cloneNode(TRUE), TRUE)); echo $document->saveHTML(); } echo "\n"; }; echo "I am using the following XPath expression to select table cells from\n"; echo "the first row of the first table, by combining the results for <th>\n"; echo "and <td>. This works fine, I get both cells back.\n"; echo "Note that the first table combines <th> and <td> in a single row.\n"; $xpath('(((descendant-or-self::html/descendant-or-self::table)[1]//tr)[1]/td|((descendant-or-self::html/descendant-or-self::table)[1]//tr)[1]/th)'); echo "When I try to get the first cell by appending [1] to the expression\n"; echo "I get the second cell back instead of the first. Why?\n"; echo "The expected result of this expression is '<th>Cell 1</th>'\n"; $xpath('(((descendant-or-self::html/descendant-or-self::table)[1]//tr)[1]/td|((descendant-or-self::html/descendant-or-self::table)[1]//tr)[1]/th)[1]'); echo "Appending [2] yields the second cell successfully. But why not the first?\n"; $xpath('(((descendant-or-self::html/descendant-or-self::table)[1]//tr)[1]/td|((descendant-or-self::html/descendant-or-self::table)[1]//tr)[1]/th)[2]'); echo "Similarly, for the second table I can get all cells with this expression.\n"; echo "The second table only contains <th> cells in the first row.\n"; $xpath('(((descendant-or-self::html/descendant-or-self::table)[2]//tr)[1]/td|((descendant-or-self::html/descendant-or-self::table)[2]//tr)[1]/th)'); echo "However, when I append [1] to get only the first cell back, I get an empty result.\n"; echo "The expected result for this expression is '<th>Cell 1</th>'\n"; $xpath('(((descendant-or-self::html/descendant-or-self::table)[2]//tr)[1]/td|((descendant-or-self::html/descendant-or-self::table)[2]//tr)[1]/th)[1]'); echo "The second cell can be retrieved successfully by appending [2].\n"; echo "But why not the first?\n"; $xpath('(((descendant-or-self::html/descendant-or-self::table)[2]//tr)[1]/td|((descendant-or-self::html/descendant-or-self::table)[2]//tr)[1]/th)[2]'); echo "Note that by replacing the first 'descendant-or-self' with '//' the expression\n"; echo "seems to work as expected in all cases for both the first and second table:\n"; $xpath('(((//html/descendant-or-self::table)[1]//tr)[1]/td|((//html/descendant-or-self::table)[1]//tr)[1]/th)'); $xpath('(((//html/descendant-or-self::table)[1]//tr)[1]/td|((//html/descendant-or-self::table)[1]//tr)[1]/th)[1]'); $xpath('(((//html/descendant-or-self::table)[1]//tr)[1]/td|((//html/descendant-or-self::table)[1]//tr)[1]/th)[2]'); $xpath('(((//html/descendant-or-self::table)[2]//tr)[1]/td|((//html/descendant-or-self::table)[2]//tr)[1]/th)'); $xpath('(((//html/descendant-or-self::table)[2]//tr)[1]/td|((//html/descendant-or-self::table)[2]//tr)[1]/th)[1]'); $xpath('(((//html/descendant-or-self::table)[2]//tr)[1]/td|((//html/descendant-or-self::table)[2]//tr)[1]/th)[2]');
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/WuPSt
function name:  (null)
number of ops:  67
compiled vars:  !0 = $xhtml, !1 = $document, !2 = $xpath
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
    6     0  E >   ASSIGN                                                   !0, '%3Chtml%3E%0A++%3Chead%3E%0A++++%3Ctitle%3ETable+test+page%3C%2Ftitle%3E%0A++%3C%2Fhead%3E%0A++%3Cbody%3E%0A++++%3Ctable%3E%0A++++++%3Ctr%3E%0A++++++++%3Cth%3ECell+1%3C%2Fth%3E%0A++++++++%3Ctd%3ECell+2%3C%2Ftd%3E%0A++++++%3C%2Ftr%3E%0A++++%3C%2Ftable%3E%0A++++%3Ctable%3E%0A++++++%3Ctr%3E%0A++++++++%3Cth%3ECell+1%3C%2Fth%3E%0A++++++++%3Cth%3ECell+2%3C%2Fth%3E%0A++++++%3C%2Ftr%3E%0A++++%3C%2Ftable%3E%0A++%3C%2Fbody%3E%0A%3C%2Fhtml%3E'
   28     1        NEW                                              $4      'DOMDocument'
          2        DO_FCALL                                      0          
          3        ASSIGN                                                   !1, $4
   29     4        INIT_METHOD_CALL                                         !1, 'loadXML'
          5        SEND_VAR_EX                                              !0
          6        DO_FCALL                                      0          
   30     7        NEW                                              $8      'DOMXPath'
          8        SEND_VAR_EX                                              !1
          9        DO_FCALL                                      0          
         10        ASSIGN                                                   !2, $8
   32    11        DECLARE_LAMBDA_FUNCTION                          ~11     [0]
         12        BIND_LEXICAL                                             ~11, !2
         13        ASSIGN                                                   !2, ~11
   53    14        ECHO                                                     'I+am+using+the+following+XPath+expression+to+select+table+cells+from%0A'
   54    15        ECHO                                                     'the+first+row+of+the+first+table%2C+by+combining+the+results+for+%3Cth%3E%0A'
   55    16        ECHO                                                     'and+%3Ctd%3E.+This+works+fine%2C+I+get+both+cells+back.%0A'
   56    17        ECHO                                                     'Note+that+the+first+table+combines+%3Cth%3E+and+%3Ctd%3E+in+a+single+row.%0A'
   57    18        INIT_DYNAMIC_CALL                                        !2
         19        SEND_VAL_EX                                              '%28%28%28descendant-or-self%3A%3Ahtml%2Fdescendant-or-self%3A%3Atable%29%5B1%5D%2F%2Ftr%29%5B1%5D%2Ftd%7C%28%28descendant-or-self%3A%3Ahtml%2Fdescendant-or-self%3A%3Atable%29%5B1%5D%2F%2Ftr%29%5B1%5D%2Fth%29'
         20        DO_FCALL                                      0          
   59    21        ECHO                                                     'When+I+try+to+get+the+first+cell+by+appending+%5B1%5D+to+the+expression%0A'
   60    22        ECHO                                                     'I+get+the+second+cell+back+instead+of+the+first.+Why%3F%0A'
   61    23        ECHO                                                     'The+expected+result+of+this+expression+is+%27%3Cth%3ECell+1%3C%2Fth%3E%27%0A'
   62    24        INIT_DYNAMIC_CALL                                        !2
         25        SEND_VAL_EX                                              '%28%28%28descendant-or-self%3A%3Ahtml%2Fdescendant-or-self%3A%3Atable%29%5B1%5D%2F%2Ftr%29%5B1%5D%2Ftd%7C%28%28descendant-or-self%3A%3Ahtml%2Fdescendant-or-self%3A%3Atable%29%5B1%5D%2F%2Ftr%29%5B1%5D%2Fth%29%5B1%5D'
         26        DO_FCALL                                      0          
   64    27        ECHO                                                     'Appending+%5B2%5D+yields+the+second+cell+successfully.+But+why+not+the+first%3F%0A'
   65    28        INIT_DYNAMIC_CALL                                        !2
         29        SEND_VAL_EX                                              '%28%28%28descendant-or-self%3A%3Ahtml%2Fdescendant-or-self%3A%3Atable%29%5B1%5D%2F%2Ftr%29%5B1%5D%2Ftd%7C%28%28descendant-or-self%3A%3Ahtml%2Fdescendant-or-self%3A%3Atable%29%5B1%5D%2F%2Ftr%29%5B1%5D%2Fth%29%5B2%5D'
         30        DO_FCALL                                      0          
   67    31        ECHO                                                     'Similarly%2C+for+the+second+table+I+can+get+all+cells+with+this+expression.%0A'
   68    32        ECHO                                                     'The+second+table+only+contains+%3Cth%3E+cells+in+the+first+row.%0A'
   69    33        INIT_DYNAMIC_CALL                                        !2
         34        SEND_VAL_EX                                              '%28%28%28descendant-or-self%3A%3Ahtml%2Fdescendant-or-self%3A%3Atable%29%5B2%5D%2F%2Ftr%29%5B1%5D%2Ftd%7C%28%28descendant-or-self%3A%3Ahtml%2Fdescendant-or-self%3A%3Atable%29%5B2%5D%2F%2Ftr%29%5B1%5D%2Fth%29'
         35        DO_FCALL                                      0          
   71    36        ECHO                                                     'However%2C+when+I+append+%5B1%5D+to+get+only+the+first+cell+back%2C+I+get+an+empty+result.%0A'
   72    37        ECHO                                                     'The+expected+result+for+this+expression+is+%27%3Cth%3ECell+1%3C%2Fth%3E%27%0A'
   73    38        INIT_DYNAMIC_CALL                                        !2
         39        SEND_VAL_EX                                              '%28%28%28descendant-or-self%3A%3Ahtml%2Fdescendant-or-self%3A%3Atable%29%5B2%5D%2F%2Ftr%29%5B1%5D%2Ftd%7C%28%28descendant-or-self%3A%3Ahtml%2Fdescendant-or-self%3A%3Atable%29%5B2%5D%2F%2Ftr%29%5B1%5D%2Fth%29%5B1%5D'
         40        DO_FCALL                                      0          
   75    41        ECHO                                                     'The+second+cell+can+be+retrieved+successfully+by+appending+%5B2%5D.%0A'
   76    42        ECHO                                                     'But+why+not+the+first%3F%0A'
   77    43        INIT_DYNAMIC_CALL                                        !2
         44        SEND_VAL_EX                                              '%28%28%28descendant-or-self%3A%3Ahtml%2Fdescendant-or-self%3A%3Atable%29%5B2%5D%2F%2Ftr%29%5B1%5D%2Ftd%7C%28%28descendant-or-self%3A%3Ahtml%2Fdescendant-or-self%3A%3Atable%29%5B2%5D%2F%2Ftr%29%5B1%5D%2Fth%29%5B2%5D'
         45        DO_FCALL                                      0          
   79    46        ECHO                                                     'Note+that+by+replacing+the+first+%27descendant-or-self%27+with+%27%2F%2F%27+the+expression%0A'
   80    47        ECHO                                                     'seems+to+work+as+expected+in+all+cases+for+both+the+first+and+second+table%3A%0A'
   81    48        INIT_DYNAMIC_CALL                                        !2
         49        SEND_VAL_EX                                              '%28%28%28%2F%2Fhtml%2Fdescendant-or-self%3A%3Atable%29%5B1%5D%2F%2Ftr%29%5B1%5D%2Ftd%7C%28%28%2F%2Fhtml%2Fdescendant-or-self%3A%3Atable%29%5B1%5D%2F%2Ftr%29%5B1%5D%2Fth%29'
         50        DO_FCALL                                      0          
   82    51        INIT_DYNAMIC_CALL                                        !2
         52        SEND_VAL_EX                                              '%28%28%28%2F%2Fhtml%2Fdescendant-or-self%3A%3Atable%29%5B1%5D%2F%2Ftr%29%5B1%5D%2Ftd%7C%28%28%2F%2Fhtml%2Fdescendant-or-self%3A%3Atable%29%5B1%5D%2F%2Ftr%29%5B1%5D%2Fth%29%5B1%5D'
         53        DO_FCALL                                      0          
   83    54        INIT_DYNAMIC_CALL                                        !2
         55        SEND_VAL_EX                                              '%28%28%28%2F%2Fhtml%2Fdescendant-or-self%3A%3Atable%29%5B1%5D%2F%2Ftr%29%5B1%5D%2Ftd%7C%28%28%2F%2Fhtml%2Fdescendant-or-self%3A%3Atable%29%5B1%5D%2F%2Ftr%29%5B1%5D%2Fth%29%5B2%5D'
         56        DO_FCALL                                      0          
   84    57        INIT_DYNAMIC_CALL                                        !2
         58        SEND_VAL_EX                                              '%28%28%28%2F%2Fhtml%2Fdescendant-or-self%3A%3Atable%29%5B2%5D%2F%2Ftr%29%5B1%5D%2Ftd%7C%28%28%2F%2Fhtml%2Fdescendant-or-self%3A%3Atable%29%5B2%5D%2F%2Ftr%29%5B1%5D%2Fth%29'
         59        DO_FCALL                                      0          
   85    60        INIT_DYNAMIC_CALL                                        !2
         61        SEND_VAL_EX                                              '%28%28%28%2F%2Fhtml%2Fdescendant-or-self%3A%3Atable%29%5B2%5D%2F%2Ftr%29%5B1%5D%2Ftd%7C%28%28%2F%2Fhtml%2Fdescendant-or-self%3A%3Atable%29%5B2%5D%2F%2Ftr%29%5B1%5D%2Fth%29%5B1%5D'
         62        DO_FCALL                                      0          
   86    63        INIT_DYNAMIC_CALL                                        !2
         64        SEND_VAL_EX                                              '%28%28%28%2F%2Fhtml%2Fdescendant-or-self%3A%3Atable%29%5B2%5D%2F%2Ftr%29%5B1%5D%2Ftd%7C%28%28%2F%2Fhtml%2Fdescendant-or-self%3A%3Atable%29%5B2%5D%2F%2Ftr%29%5B1%5D%2Fth%29%5B2%5D'
         65        DO_FCALL                                      0          
         66      > RETURN                                                   1


Dynamic Functions:
Dynamic Function 0
Finding entry points
Branch analysis from position: 0
2 jumps found. (Code = 43) Position 1 = 13, Position 2 = 17
Branch analysis from position: 13
1 jumps found. (Code = 42) Position 1 = 27
Branch analysis from position: 27
2 jumps found. (Code = 43) Position 1 = 30, Position 2 = 32
Branch analysis from position: 30
1 jumps found. (Code = 42) Position 1 = 33
Branch analysis from position: 33
2 jumps found. (Code = 43) Position 1 = 35, Position 2 = 37
Branch analysis from position: 35
1 jumps found. (Code = 42) Position 1 = 38
Branch analysis from position: 38
2 jumps found. (Code = 77) Position 1 = 42, Position 2 = 60
Branch analysis from position: 42
2 jumps found. (Code = 78) Position 1 = 43, Position 2 = 60
Branch analysis from position: 43
1 jumps found. (Code = 42) Position 1 = 42
Branch analysis from position: 42
Branch analysis from position: 60
1 jumps found. (Code = 62) Position 1 = -2
Branch analysis from position: 60
Branch analysis from position: 37
2 jumps found. (Code = 77) Position 1 = 42, Position 2 = 60
Branch analysis from position: 42
Branch analysis from position: 60
Branch analysis from position: 32
2 jumps found. (Code = 43) Position 1 = 35, Position 2 = 37
Branch analysis from position: 35
Branch analysis from position: 37
Branch analysis from position: 17
2 jumps found. (Code = 43) Position 1 = 30, Position 2 = 32
Branch analysis from position: 30
Branch analysis from position: 32
filename:       /in/WuPSt
function name:  {closure}
number of ops:  63
compiled vars:  !0 = $query, !1 = $xpath, !2 = $result, !3 = $count, !4 = $result_array, !5 = $element, !6 = $document
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   32     0  E >   RECV                                             !0      
          1        BIND_STATIC                                              !1
   33     2        CONCAT                                           ~7      !0, '%0A'
          3        ECHO                                                     ~7
   34     4        INIT_METHOD_CALL                                         !1, 'query'
          5        SEND_VAR_EX                                              !0
          6        DO_FCALL                                      0  $8      
          7        ASSIGN                                                   !2, $8
   35     8        INIT_FCALL                                               'method_exists'
          9        SEND_VAR                                                 !2
         10        SEND_VAL                                                 'count'
         11        DO_ICALL                                         $10     
         12      > JMPZ                                                     $10, ->17
   36    13    >   INIT_METHOD_CALL                                         !2, 'count'
         14        DO_FCALL                                      0  $11     
         15        ASSIGN                                                   !3, $11
   35    16      > JMP                                                      ->27
   39    17    >   INIT_FCALL                                               'iterator_to_array'
         18        SEND_VAR                                                 !2
         19        DO_ICALL                                         $13     
         20        ASSIGN                                                   !4, $13
   41    21        INIT_FCALL                                               'array_filter'
         22        SEND_VAR                                                 !4
         23        DO_ICALL                                         $15     
         24        ASSIGN                                                   !4, $15
   42    25        COUNT                                            ~17     !4
         26        ASSIGN                                                   !3, ~17
   44    27    >   CONCAT                                           ~19     !3, '+result'
         28        IS_NOT_EQUAL                                             !3, 1
         29      > JMPZ                                                     ~20, ->32
         30    >   QM_ASSIGN                                        ~21     's'
         31      > JMP                                                      ->33
         32    >   QM_ASSIGN                                        ~21     ''
         33    >   CONCAT                                           ~22     ~19, ~21
         34      > JMPZ                                                     !3, ->37
         35    >   QM_ASSIGN                                        ~23     '%3A'
         36      > JMP                                                      ->38
         37    >   QM_ASSIGN                                        ~23     ''
         38    >   CONCAT                                           ~24     ~22, ~23
         39        CONCAT                                           ~25     ~24, '%0A'
         40        ECHO                                                     ~25
   45    41      > FE_RESET_R                                       $26     !2, ->60
         42    > > FE_FETCH_R                                               $26, !5, ->60
   46    43    >   NEW                                              $27     'DOMDocument'
         44        DO_FCALL                                      0          
         45        ASSIGN                                                   !6, $27
   47    46        INIT_METHOD_CALL                                         !6, 'appendChild'
         47        INIT_METHOD_CALL                                         !6, 'importNode'
         48        INIT_METHOD_CALL                                         !5, 'cloneNode'
         49        SEND_VAL_EX                                              <true>
         50        DO_FCALL                                      0  $30     
         51        SEND_VAR_NO_REF_EX                                       $30
         52        SEND_VAL_EX                                              <true>
         53        DO_FCALL                                      0  $31     
         54        SEND_VAR_NO_REF_EX                                       $31
         55        DO_FCALL                                      0          
   48    56        INIT_METHOD_CALL                                         !6, 'saveHTML'
         57        DO_FCALL                                      0  $33     
         58        ECHO                                                     $33
   45    59      > JMP                                                      ->42
         60    >   FE_FREE                                                  $26
   50    61        ECHO                                                     '%0A'
   51    62      > RETURN                                                   null

End of Dynamic Function 0

Generated using Vulcan Logic Dumper, using php 8.0.0


preferences:
138.48 ms | 1019 KiB | 16 Q