Php 将数据从同级检索到匹配的节点

Php 将数据从同级检索到匹配的节点,php,xml,xpath,simplexml,siblings,Php,Xml,Xpath,Simplexml,Siblings,我正在使用SimpleXML迭代xml文档。我有一个id为的数组($ids),我正在检查XML(工作表/表/行/单元格/数据)中是否有匹配项。如果是匹配的话,我希望能够从以下两个兄弟姐妹那里获得数据,但我不知道怎么做 来自php: // $ids <---- array('8', '53', '38') foreach ($thePositions->Worksheet->Table->Row as $row) { if($row->Cell->D

我正在使用SimpleXML迭代xml文档。我有一个id为的数组($ids),我正在检查XML(工作表/表/行/单元格/数据)中是否有匹配项。如果是匹配的话,我希望能够从以下两个兄弟姐妹那里获得数据,但我不知道怎么做

来自php:

// $ids <---- array('8', '53', '38')

foreach ($thePositions->Worksheet->Table->Row as $row) {

    if($row->Cell->Data == true) {

        for ($i = 0; $i < count($ids); $i++) {
            foreach($row->Cell->Data as $data) {

                if ($data == $ids[$i]) {
                    echo 'match!';

                    /* 
                       Tried $siblings = $data->xpath('preceding-sibling::* | following-sibling::*');
                       but doesn't seem to work in this case.
                    */
                }
            }
        }
    }
}
<?xml version="1.0"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
 xmlns:o="urn:schemas-microsoft-com:office:office"
 xmlns:x="urn:schemas-microsoft-com:office:excel"
 xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
 xmlns:html="http://www.w3.org/TR/REC-html40">
 <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
  <LastAuthor>Herpa Derp </LastAuthor>
  <Created>2012-09-25T13:44:01Z</Created>
  <LastSaved>2012-09-25T13:48:24Z</LastSaved>
  <Version>14.0</Version>
 </DocumentProperties>
 <OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">
  <AllowPNG/>
 </OfficeDocumentSettings>
 <ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
  <WindowHeight>14060</WindowHeight>
  <WindowWidth>25040</WindowWidth>
  <WindowTopX>25540</WindowTopX>
  <WindowTopY>4100</WindowTopY>
  <Date1904/>
  <ProtectStructure>False</ProtectStructure>
  <ProtectWindows>False</ProtectWindows>
 </ExcelWorkbook>
 <Styles>
  <Style ss:ID="Default" ss:Name="Normal">
   <Alignment ss:Vertical="Bottom"/>
   <Borders/>
   <Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000"/>
   <Interior/>
   <NumberFormat/>
   <Protection/>
  </Style>
  <Style ss:ID="s62">
   <Font ss:FontName="Courier" ss:Color="#000000"/>
  </Style>
 </Styles>
 <Worksheet ss:Name="Workbook1.csv">
  <Table ss:ExpandedColumnCount="5" ss:ExpandedRowCount="79" x:FullColumns="1"
   x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="15">
   <Column ss:Index="2" ss:AutoFitWidth="0" ss:Width="43"/>
   <Column ss:AutoFitWidth="0" ss:Width="113"/>
   <Column ss:Index="5" ss:AutoFitWidth="0" ss:Width="220"/>
   <Row ss:Index="6">
    <Cell ss:Index="3" ss:StyleID="s62"/>
   </Row>
   <Row>
    <Cell ss:Index="3" ss:StyleID="s62"/>
   </Row>
   <Row>
    <Cell ss:Index="3" ss:StyleID="s62"/>
   </Row>
   <Row>
    <Cell ss:Index="2"><Data ss:Type="String">id</Data></Cell>
    <Cell ss:StyleID="s62"><Data ss:Type="String">latitude</Data></Cell>
    <Cell><Data ss:Type="String">longitude</Data></Cell>
   </Row>
   <Row>
    <Cell ss:Index="2"><Data ss:Type="Number">8</Data></Cell>
    <Cell ss:StyleID="s62"><Data ss:Type="Number">57.4999</Data></Cell>    // to be saved to $latutude
    <Cell><Data ss:Type="Number">15.8280</Data></Cell>    // to be saved to $longitude
   </Row>
   <Row>
    <Cell ss:Index="2"><Data ss:Type="Number">38</Data></Cell>
    <Cell><Data ss:Type="Number">56.5659</Data></Cell>
    <Cell><Data ss:Type="Number">16.1380</Data></Cell>
   </Row>
/$ids工作表->表格->行作为$Row){
如果($row->Cell->Data==true){
对于($i=0;$iCell->Data as$Data){
如果($data==$ids[$i]){
回声“匹配!”;
/* 
尝试了$SIBLINES=$data->xpath('previous-sibling::*| following-sibling::*');
但在这种情况下似乎不起作用。
*/
}
}
}
}
}
xml:

// $ids <---- array('8', '53', '38')

foreach ($thePositions->Worksheet->Table->Row as $row) {

    if($row->Cell->Data == true) {

        for ($i = 0; $i < count($ids); $i++) {
            foreach($row->Cell->Data as $data) {

                if ($data == $ids[$i]) {
                    echo 'match!';

                    /* 
                       Tried $siblings = $data->xpath('preceding-sibling::* | following-sibling::*');
                       but doesn't seem to work in this case.
                    */
                }
            }
        }
    }
}
<?xml version="1.0"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
 xmlns:o="urn:schemas-microsoft-com:office:office"
 xmlns:x="urn:schemas-microsoft-com:office:excel"
 xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
 xmlns:html="http://www.w3.org/TR/REC-html40">
 <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
  <LastAuthor>Herpa Derp </LastAuthor>
  <Created>2012-09-25T13:44:01Z</Created>
  <LastSaved>2012-09-25T13:48:24Z</LastSaved>
  <Version>14.0</Version>
 </DocumentProperties>
 <OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">
  <AllowPNG/>
 </OfficeDocumentSettings>
 <ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
  <WindowHeight>14060</WindowHeight>
  <WindowWidth>25040</WindowWidth>
  <WindowTopX>25540</WindowTopX>
  <WindowTopY>4100</WindowTopY>
  <Date1904/>
  <ProtectStructure>False</ProtectStructure>
  <ProtectWindows>False</ProtectWindows>
 </ExcelWorkbook>
 <Styles>
  <Style ss:ID="Default" ss:Name="Normal">
   <Alignment ss:Vertical="Bottom"/>
   <Borders/>
   <Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000"/>
   <Interior/>
   <NumberFormat/>
   <Protection/>
  </Style>
  <Style ss:ID="s62">
   <Font ss:FontName="Courier" ss:Color="#000000"/>
  </Style>
 </Styles>
 <Worksheet ss:Name="Workbook1.csv">
  <Table ss:ExpandedColumnCount="5" ss:ExpandedRowCount="79" x:FullColumns="1"
   x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="15">
   <Column ss:Index="2" ss:AutoFitWidth="0" ss:Width="43"/>
   <Column ss:AutoFitWidth="0" ss:Width="113"/>
   <Column ss:Index="5" ss:AutoFitWidth="0" ss:Width="220"/>
   <Row ss:Index="6">
    <Cell ss:Index="3" ss:StyleID="s62"/>
   </Row>
   <Row>
    <Cell ss:Index="3" ss:StyleID="s62"/>
   </Row>
   <Row>
    <Cell ss:Index="3" ss:StyleID="s62"/>
   </Row>
   <Row>
    <Cell ss:Index="2"><Data ss:Type="String">id</Data></Cell>
    <Cell ss:StyleID="s62"><Data ss:Type="String">latitude</Data></Cell>
    <Cell><Data ss:Type="String">longitude</Data></Cell>
   </Row>
   <Row>
    <Cell ss:Index="2"><Data ss:Type="Number">8</Data></Cell>
    <Cell ss:StyleID="s62"><Data ss:Type="Number">57.4999</Data></Cell>    // to be saved to $latutude
    <Cell><Data ss:Type="Number">15.8280</Data></Cell>    // to be saved to $longitude
   </Row>
   <Row>
    <Cell ss:Index="2"><Data ss:Type="Number">38</Data></Cell>
    <Cell><Data ss:Type="Number">56.5659</Data></Cell>
    <Cell><Data ss:Type="Number">16.1380</Data></Cell>
   </Row>

赫帕·德普
2012-09-25T13:44:01Z
2012-09-25T13:48:24Z
14
14060
25040
25540
4100
假的
假的
身份证件
纬度
经度
8.
57.4999//将保存到$latutude
15.8280//将保存到$longitude
38
56.5659
16.1380

对于此XML,单元格的顺序始终相同,因此可以按如下方式进行操作:

$ids = array('8', '53', '38');
foreach ($xml->Worksheet->Table->Row as $row) {
    $children = $row->children();
    if (count($children) == 3 && in_array(((string) $children[0]->Data), $ids)) {
        echo 'lat: ' . $children[1]->Data . ' lng: ' . $children[2]->Data . "\n";
    }
}

请求兄弟元素不起作用的原因是
元素不是兄弟元素;他们更像是近亲——相邻
元素的孩子

出于同样的原因,您不应该使用
foreach($row->Cell->Data as$Data)
,因为这相当于
foreach($row->Cell[0]->Data as$Data)
,即查看第一个
节点的所有
子节点。由于一个
中只有一个
元素,因此您最好只编写
$data=$row->Cell[0]->data
——在本例中,这样做很好,因为您要查找的值位于行的开头

实际上,您需要做的是在
s:
foreach($row->Cell as$Cell){$data=$Cell->data;/*…*/}

然后,您有两个用于查找相邻单元格的选项,包括XPath。更“PHP化”的方法是使用数组索引(同级在SimpleXML循环/数组访问中以数字形式索引):

或者,您可以依赖ID始终位于第一列,lat和long位于下两列(毕竟这是一个电子表格!),并完全避免内部循环:

if ( $row->Cell[0]->Data == $ids[$i] )
{
    $latitudes[$i] = (string)$row->Cell[1]->Data;
    $longitudes[$i] = (string)$row->Cell[2]->Data;
}

您可以完全在XPath中完成,无需任何循环,如:

//Row[Cell/Data[. = '8' or . = '53' or . = '38']]/following-sibling::*[position() <= 2]

//Row[Cell/Data[.='8'或.='53'或.='38']]/以下同级::*[position()如果要匹配大量ID,另一种方法是根据所有行的ID创建一个“哈希”,然后查看该哈希,而不是循环搜索匹配项

// Initialise an empty array to use as the hash
$rows_by_id = array();

// Loop over all the rows in the spreadsheet
foreach ($thePositions->Worksheet->Table->Row as $row) {
    // Skip rows with less than 3 cells
    if ( count($row->Cell) < 3 ) {
        continue;
    }

    // Take the ID from the first cell on the row
    $id = (string)$row->Cell[0]->Data;

    // Add this row to the hash, identified by it's ID
    $rows_by_id[$id] = array(
        'latitude'  => (string)$row->Cell[1]->Data,
        'longitude' => (string)$row->Cell[2]->Data
    );

    // Or if your IDs are not unique, and you want all matches:
    // $rows_by_id[$id][] = array( ... )
}

foreach ( $ids  as $required_id ) {
    // Retrieve the results from the hash
    if ( isset($rows_by_id[$required_id]) ) { 
        $matched_row = $rows_by_id[$required_id];

        echo "ID $required_id has latitude {$matched_row['latitude']} and longitude {$matched_row['longitude']}.\n";
    }
    else {
        echo "ID $required_id was not matched. :(\n";
    }

    // If you have non-unique matches, you'll need something like this:
    // $all_matched_rows = $rows_by_id[$required_id]; ... foreach ( $all_matched_rows as $matched_row )
}
//初始化一个空数组以用作哈希
$rows_by_id=array();
//循环浏览电子表格中的所有行
foreach($thePositions->worket->Table->Row as$Row){
//跳过少于3个单元格的行
如果(计数($row->Cell)<3){
继续;
}
//从行的第一个单元格中获取ID
$id=(字符串)$row->单元格[0]->数据;
//将此行添加到哈希中,由其ID标识
$rows\u by\u id[$id]=数组(
“纬度”=>(字符串)$row->单元格[1]->数据,
“经度”=>(字符串)$row->单元格[2]->数据
);
//或者如果您的ID不唯一,并且您希望所有匹配项:
//$rows\u by_id[$id][]=数组(…)
}
foreach($id作为$required\u id){
//从散列中检索结果
if(isset($rows\u by\u id[$required\u id]){
$matched_row=$rows_by_id[$required_id];
echo“ID$required_ID具有纬度{$matched_row['latitude']}和经度{$matched_row['longitude']}。\n”;
}
否则{
echo“ID$必需\u ID不匹配:(\n”;
}
//如果您有非唯一匹配项,则需要以下内容:
//$all_matched_rows=$rows_by_id[$required_id];…foreach($all_matched_rows作为$matched_row)
}

XML
namespace定义什么不起作用?结果太多?没有结果?您可以像
//行[Cell/Data[.='8'或.='53'或.='38']]那样在XPath中完全运行它/以下同级:*[position()@BeniBela为什么这是一个评论而不是一个答案,如果它解决了提出的问题?@IMSoP:因为我们不知道他的问题到底是什么。他说,他想要下面的兄弟姐妹,但评论也读了前面的兄弟姐妹…如果有命名空间问题,它将不起作用。@BeniBela这个问题包括一个相当清楚的例子,反对你可以测试你的代码,对我来说似乎很清楚。有趣的方法。不过我有几个问题。1.在你的代码中,你明确地寻找id的8、53和38,但它可以是任何id(1或多个)在$ids内。我可以将变量直接放在XPath代码内吗?2.我想将id及其位置保存在多维数组中,如何使用您的代码进行保存?提前感谢!1:在XPath 2中可以,我不知道您是否可以直接在XPath 1中进行此操作。但是您可以动态构造查询
“=”。内爆(“'或.=',$ids)。”“
2:XPath不支持多维数组。您可以从查询中删除以下-同级以获取所有匹配行,然后使用php中的dom函数获取它们的下一个同级。非常感谢您的详细解释。我知道我理解代码中的问题。我已经实现了您的代码(尝试了这两种方法)“versions”),但有一个问题我想知道如何解决,那就是通过$ids中的id进行迭代。我尝试将代码放入for循环中,这意味着我对每一行的所有单元格节点进行迭代
// Initialise an empty array to use as the hash
$rows_by_id = array();

// Loop over all the rows in the spreadsheet
foreach ($thePositions->Worksheet->Table->Row as $row) {
    // Skip rows with less than 3 cells
    if ( count($row->Cell) < 3 ) {
        continue;
    }

    // Take the ID from the first cell on the row
    $id = (string)$row->Cell[0]->Data;

    // Add this row to the hash, identified by it's ID
    $rows_by_id[$id] = array(
        'latitude'  => (string)$row->Cell[1]->Data,
        'longitude' => (string)$row->Cell[2]->Data
    );

    // Or if your IDs are not unique, and you want all matches:
    // $rows_by_id[$id][] = array( ... )
}

foreach ( $ids  as $required_id ) {
    // Retrieve the results from the hash
    if ( isset($rows_by_id[$required_id]) ) { 
        $matched_row = $rows_by_id[$required_id];

        echo "ID $required_id has latitude {$matched_row['latitude']} and longitude {$matched_row['longitude']}.\n";
    }
    else {
        echo "ID $required_id was not matched. :(\n";
    }

    // If you have non-unique matches, you'll need something like this:
    // $all_matched_rows = $rows_by_id[$required_id]; ... foreach ( $all_matched_rows as $matched_row )
}