Search code examples
phpxpathsimplexmlancestor

How to get parent node with xpath using simpleXML (php)


I have problems with an XML file.

Here it is :

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
<sheetPr codeName="Feuil3">
    <tabColor rgb="FF00B050"/>
</sheetPr>
<dimension ref="A18"/>
<sheetViews>
    <sheetView tabSelected="1" topLeftCell="A3" workbookViewId="0">
        <selection activeCell="A3" sqref="A3"/>
    </sheetView>
</sheetViews>
<sheetFormatPr baseColWidth="10" defaultRowHeight="15"/>
    <cols>
        <col min="1" max="1" width="29.140625" bestFit="1" customWidth="1"/>
        <col min="2" max="2" width="24.42578125" bestFit="1" customWidth="1"/>
        <col min="3" max="3" width="14.28515625" bestFit="1" customWidth="1"/>
        <col min="4" max="4" width="5.42578125" bestFit="1" customWidth="1"/>
        <col min="5" max="5" width="6.140625" bestFit="1" customWidth="1"/>
    </cols>

<sheetData>
    <row r="18" ht="16.5" customHeight="1"/>
</sheetData>
<sortState ref="A2:E1036">
    <sortCondition descending="1" ref="C1"/>
</sortState>
<pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3"/>
</worksheet>

I would like to have the parent node (row) with this xpath restrictions (that work) :

$row2 = $xml->xpath("//*[local-name()='row']/@*[local-name()='r' and .= '18']");

For now it returns me this :

array(1) {
  [0]=>
  object(SimpleXMLElement)#383 (1) {
    ["@attributes"]=>
    array(1) {
      ["r"]=>
      string(2) "18"
    }
  }
}

I would like to have the parent.. (row)

How should I do ?

Thanks a lot.


Solution

  • On thing first. To get rid of the local-name() and stop ignoring the namespace, register a prefix for it. After that it is just a simple condition.

    $worksheet = new SimpleXMLElement($xml);
    $worksheet->registerXpathNamespace(
      'm', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'
    );
    
    var_dump(
      $worksheet->xpath('//m:row[@r=18]')
    );
    

    Output:

    array(1) {
      [0]=>
      object(SimpleXMLElement)#2 (1) {
        ["@attributes"]=>
        array(3) {
          ["r"]=>
          string(2) "18"
          ["ht"]=>
          string(4) "16.5"
          ["customHeight"]=>
          string(1) "1"
        }
      }
    }
    

    SimpleXMLElement::xpath() will always return an array. Here could be several or no row element. Use an condition to validate that you fetched a node or use a loop to iterate over the array.

    The expression in this case contains of two parts: //m:row fetch any row element node in the document. [] contains filter conditions for the found nodes. In this case @id=18, the attribute node id should equal 18.