LMLPHP后院

使用php函数simplexml_load_string解析xml注意事项技术

maybe yes 发表于 2016-10-24 23:17

PHP 解析 xml 的方法有很多种,比如 DOMDocument 的 xpath,XMLReader,SimpleXML,XML Expat Parser 等。一般情况下,解析一段格式比较规则的 xml,程序员字符的处理能力比较强的话,自己写一个解析器也未尝不可。大多数情况下,使用面向对象的库来解析 xml 是不太方便的,不如函数来的爽快。

使用函数 simplexml_load_string 的坑

文本讲述 PHP 函数 simplexml_load_string 解析 xml 的注意事项。对于提交比较小的 xml,使用此函数解析是再适合不过啦。关于此函数的坑,请看如下代码

<?php

$xml_str = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><MasMessage xmlns="http://www.99bill.com/mas_cnp_merchant_interface"><PciQueryContent><merchantId>812310060110237</merchantId><customerId>181</customerId><storablePan></storablePan><cardType>0002</cardType><pciInfos><pciInfo><bankId>CMB</bankId><storablePan>6214830385</storablePan><shortPhoneNo>1564872</shortPhoneNo><phoneNO>15601664872</phoneNO></pciInfo></pciInfos><responseCode>00</responseCode></PciQueryContent></MasMessage>';
$s = simplexml_load_string($xml_str);
var_dump($s);

echo "---------\n";

$xml_str = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><MasMessage xmlns="http://www.99bill.com/mas_cnp_merchant_interface"><PciQueryContent><merchantId>812310060110237</merchantId><customerId>181</customerId><storablePan></storablePan><cardType>0002</cardType><pciInfos><pciInfo><bankId>CMB</bankId><storablePan>6214830385</storablePan><shortPhoneNo>1564872</shortPhoneNo><phoneNO>15601664872</phoneNO></pciInfo><pciInfo><bankId>CMB</bankId><storablePan>6214830385</storablePan><shortPhoneNo>1564872</shortPhoneNo><phoneNO>15601664872</phoneNO></pciInfo></pciInfos><responseCode>00</responseCode></PciQueryContent></MasMessage>';
$s = simplexml_load_string($xml_str);
var_dump($s);


/**
object(SimpleXMLElement)#5 (1) {
  ["PciQueryContent"]=>
  object(SimpleXMLElement)#7 (6) {
    ["merchantId"]=>
    string(15) "812310060110237"
    ["customerId"]=>
    string(3) "181"
    ["storablePan"]=>
    object(SimpleXMLElement)#8 (0) {
    }
    ["cardType"]=>
    string(4) "0002"
    ["pciInfos"]=>
    object(SimpleXMLElement)#9 (1) {
      ["pciInfo"]=>
      object(SimpleXMLElement)#10 (4) {
        ["bankId"]=>
        string(3) "CMB"
        ["storablePan"]=>
        string(10) "6214830385"
        ["shortPhoneNo"]=>
        string(7) "1564872"
        ["phoneNO"]=>
        string(11) "15601664872"
      }
    }
    ["responseCode"]=>
    string(2) "00"
  }
}
---------
object(SimpleXMLElement)#7 (1) {
  ["PciQueryContent"]=>
  object(SimpleXMLElement)#5 (6) {
    ["merchantId"]=>
    string(15) "812310060110237"
    ["customerId"]=>
    string(3) "181"
    ["storablePan"]=>
    object(SimpleXMLElement)#9 (0) {
    }
    ["cardType"]=>
    string(4) "0002"
    ["pciInfos"]=>
    object(SimpleXMLElement)#8 (1) {
      ["pciInfo"]=>
      array(2) {
        [0]=>
        object(SimpleXMLElement)#10 (4) {
          ["bankId"]=>
          string(3) "CMB"
          ["storablePan"]=>
          string(10) "6214830385"
          ["shortPhoneNo"]=>
          string(7) "1564872"
          ["phoneNO"]=>
          string(11) "15601664872"
        }
        [1]=>
        object(SimpleXMLElement)#11 (4) {
          ["bankId"]=>
          string(3) "CMB"
          ["storablePan"]=>
          string(10) "6214830385"
          ["shortPhoneNo"]=>
          string(7) "1564872"
          ["phoneNO"]=>
          string(11) "15601664872"
        }
      }
    }
    ["responseCode"]=>
    string(2) "00"
  }
}
*/

解决方案示例

从上面的代码示例可以看出,pciInfos 下面的 pciInfo 有些情况下是对象,有些情况下是数组。这样就对后续处理的代码的写法增加了难度了。所以,写代码需要小心翼翼的。如下解决方法

$infos = (array)$s->PciQueryContent->pciInfos;

$cardsArr = (array)$infos;
if (is_array($cardsArr['pciInfo'])) {
    $cardsArr = $cardsArr['pciInfo'];
}

先将 pciInfos 转成数组,然后再通过 is_array 判断来获得多维卡信息数据,方便后续的遍历操作

组装 xml 注意事项

另外,在组装 xml 数据时也需要格外小心,比如在标签的内容中出现 & 符号,这个对于正常人来讲,都认为是能被正常解析的,但是某些比较轴的 xml 解析器是不认的,并且还不报错。

2024-04-20 21:47:18 1713620838 0.009663