从XML文档创建PHP类或对象

时间:2015-03-23 20:55:49

标签: php arrays xml class loops

我正在使用API​​返回的XML文档。 XML返回一个产品列表,其中包含每个项目的属性,如库存,项目编号,名称,价格等。

我可以遍历所有XML表,创建所有产品的列表,并显示相应的字段。问题是,我需要能够定义某些产品及其变量。

如何从XML产品创建类或数组,但仅限于某些类?例如,可能有40件产品退回,但我可能只需要其中的3件。数组或类必须包含产品的所有相关信息。

Here's a link to an example of the raw XML returned by the API

XML的一个例子是

<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<NewDataSet xmlns="">
    <Table diffgr:id="Table1" msdata:rowOrder="0">
        <ChargeDescID>14249</ChargeDescID>
        <sChgDesc>Cleaning Deposit</sChgDesc>
        <dcPrice>0.0000</dcPrice>
        <dcTax1Rate>0</dcTax1Rate>
        <dcTax2Rate>0</dcTax2Rate>
        <dcInStock>0.0000</dcInStock>
    </Table>
    <Table diffgr:id="Table2" msdata:rowOrder="1">
        <ChargeDescID>14251</ChargeDescID>
        <sChgDesc>Utility Knife</sChgDesc>
        <dcPrice>2.9900</dcPrice>
        <dcTax1Rate>9</dcTax1Rate>
        <dcTax2Rate>0</dcTax2Rate>
        <dcInStock>0.0000</dcInStock>
    </Table>
</NewDataSet>

因此,使用上面代码中的第二个产品作为示例,我想要一个PHP函数,它将创建一个类或这样的数组:

$utility_knife (
  "ChargeDescID" => "14251",
  "dcPrice" => "2.99",
  "dcTax1Rate" => "9",
  "dcTax2Rate" => "0",
  "dcInStock" => "0",
 )

如何提取特定的diffgr表并将它们格式化为命名数组或类,忽略我不需要的表?如何在忽略其他表的同时获取表的内容?

编辑以包含我尝试过的内容:

我已经能够使用loadXML()和DOMXPath将它们拉入数组,如下所示:

$dom = new DOMDocument;
$dom->loadXML($result);
$xpath = new DOMXPath($dom);
$el = $xpath->query('//Table');

#loop through results
foreach($el as $units) {

    $ChargeDescID = $xpath->query('ChargeDescID', $units)->item(0)->nodeValue;
    $sChgDesc = $xpath->query('sChgDesc', $units)->item(0)->nodeValue;
    $dcPrice = $xpath->query('dcPrice', $units)->item(0)->nodeValue;
    $dcTax1Rate = $xpath->query('dcTax1Rate', $units)->item(0)->nodeValue;
    $dcTax2Rate = $xpath->query('dcTax2Rate', $units)->item(0)->nodeValue;
    $dcInStock = $xpath->query('dcInStock', $units)->item(0)->nodeValue;

    #create oragnized array for results
    $iterate_list = array("ChargeDescID"=>$ChargeDescID,"sChgDesc"=>$sChgDesc, "dcPrice"=>$dcPrice, "dcTax1Rate"=>$dcTax1Rate, "dcTax2Rate"=>$dcTax2Rate, "dcInStock"=>$dcInStock);
    #create/append array of array
    $results_list[] = $iterate_list;

}

所以现在我有一个名为$ results_list的数组,子数组以$ key / $ value对组织,但数组本身没有命名。我可以这样有条理地打印出结果:

        foreach($results_list as $key => $value) {

    echo 
        "Charge Description ID: " . $results_list[$key]["ChargeDescID"] . "<br>" .
        "Item Description: " . $results_list[$key]["sChgDesc"] . "<br>" .
        "Item Price: " . $results_list[$key]["dcPrice"] . "<br>" .
        "Tax rate 1: " . $results_list[$key]["dcTax1Rate"] . "<br>" .
        "tax rate 2: " . $results_list[$key]["dcTax2Rate"] . "<br>" .
        "In Stock: " . $results_list[$key]["dcInStock"] . "<br>"
        ;
    }

编辑:我在下面提出的解决方案有效。我目前正在使用它,但我愿意接受更优雅的解决方案。优选地,直接选择节点而不需要条件逻辑。你提出了一些可行的方法。我正在等待他的澄清。

问题在于我无法弄清楚如何获得特定产品。我知道我可以使用数组索引,但索引可能会从一个拉到下一个拉。我想我需要某种类似于:

的功能
foreach($results_list as $key => $value){
  if ( $results_list[$key]["sChgDesc"] == "Utility Knife" ) {
    $utility_knife = array(
      "sChgDesc" => $results_list[$key]["sChgDesc"],
      "dcPrice" => $results_list[$key]["dcPrice"],
      "dcTax1Rate" => $results_list[$key]["dcTax1Rate"],
      "dcInStock" => $results_list[$key]["dcInStock"],
  );

然后在数组中写出我需要的每个产品的if语句。那是对的吗?

我已经尝试过多次这样做,因为我开始迷惑自己。我不确定是否可以在其中一个子数组值上调用if语句,然后如果值存在则循环返回该特定子数组中的其余值。

需要挑选的标准是我必须能够确定我选择的产品。所以它可能依赖于ChargeDescID或sChgDesc,但实际上并不依赖于其他任何东西。然后我需要确保填充其他相关字段。

2 个答案:

答案 0 :(得分:2)

您已经在使用XPath,但它可以做更多事情。 DOMXpath :: query()也是有限的。使用DOMXpath :: evaluate() - 它可以返回标量值。

例如:

$ChargeDescID = $xpath->query('ChargeDescID', $units)->item(0)->nodeValue;

可以重构为:

$ChargeDescID = $xpath->evaluate('string(ChargeDescID)', $units);

XPath可以包含复杂的条件。假设您要使用Table属性diffgr:id获取Table1个元素节点:

$xpath->registerNamespace('diffgr', 'urn:schemas-microsoft-com:xml-diffgram-v1');
$el = $xpath->evaluate('//Table[@diffgr:id="Table1"]');

XPath没有默认命名空间,因此如果要在不同的命名空间中寻址节点,则需要为空命名空间(xmlns="")注册一个前缀。这可以是与文档中相同的前缀或不同的前缀。

另一方面,您可以按名称或更通用的方式获取节点。 *表示任何元素节点。

$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXPath($dom);
$xpath->registerNamespace('diffgr', 'urn:schemas-microsoft-com:xml-diffgram-v1');
$el = $xpath->evaluate('//Table[@diffgr:id="Table1"]');

$results_list = [];
foreach ($el as $units) {
  $iterate_list = [];
  foreach ($xpath->evaluate('*', $units) as $valueNode) {
    $iterate_list[$valueNode->localName] = $valueNode->nodeValue;
  }
  $results_list[] = $iterate_list;
}    
var_dump($results_list);

输出:

array(1) {
  [0]=>
  array(6) {
    ["ChargeDescID"]=>
    string(5) "14249"
    ["sChgDesc"]=>
    string(16) "Cleaning Deposit"
    ["dcPrice"]=>
    string(6) "0.0000"
    ["dcTax1Rate"]=>
    string(1) "0"
    ["dcTax2Rate"]=>
    string(1) "0"
    ["dcInStock"]=>
    string(6) "0.0000"
  }
}

答案 1 :(得分:-1)

你已经尝试过这个:

 $xml = simplexml_load_file('file_xml.xml');

 print '<pre>';

 print_r($xml);

print_r仅用于调试