【问题标题】:Loop xml with namespace in PHP在 PHP 中使用命名空间循环 xml
【发布时间】:2019-08-31 15:44:29
【问题描述】:

我正在尝试在 PHP 中读取带有命名空间的 xml 元素,但我遇到了一些问题,可能是因为存在多个子节点和存在命名空间。事实上,我对没有命名空间的 xml 文件没有任何问题。

我想找到一种优雅的方式来循环节点内的信息,例如我想读取元素“费用”内的所有数据(日期、商店、iditem、价格..)并可能插入它们在一个数组里面。 这是xml:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
  <Response xmlns="http://www.w3.org/2001/XMLSchema-instance">
     <Result xmlns:a="http://www.w3.org/2001/XMLSchema-instance" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <Success xmlns="http://www.w3.org/2001/XMLSchema-instance">OK</Success>
        <a:Name>John</a:Name>
        <a:Surname>Doe</a:Surname>

        <a:Expenses>

           <a:Expense>
              <a:Date>2019-01-01</a:Date>
              <a:Store>MALL1</a:Store>                 
              <a:Items>
                 <a:Item>
                    <a:IdItem>A1</a:IdItem>
                    <a:Price>5</a:Price>
                 </a:Item>
              </a:Items>
           </a:Expense>

           <a:Expense>
              <a:Date>2019-01-02</a:Date>
              <a:Store>MALL2</a:Store>                 
              <a:Items>
                 <a:Item>
                    <a:IdItem>A2</a:IdItem>
                    <a:Price>1</a:Price>
                 </a:Item>
                 <a:Item>
                    <a:IdItem>A3</a:IdItem>
                    <a:Price>3</a:Price>
                 </a:Item>
              </a:Items>
           </a:Expense>     

        </a:Expenses>
     </Result>
  </Response>

我尝试过这样的事情:

$info= new SimpleXMLElement($xml);
$info->registerXPathNamespace('s', 'http://example.com');
$info->registerXPathNamespace('a', 'http://www.w3.org/2001/XMLSchema-instance');

//Example 1:
foreach($info->xpath('//a:Name') as $header)
{
    echo (string) $header; 
}
//Result is: John                   

//Example 2:                    
foreach($info->xpath('//a:Expenses') as $header)
{
    $array = $header->xpath('//a:Expense/a:Store'); 
    print_r($array);
}

//Result is:
/*Array
(
[0] => SimpleXMLElement Object
    (
        [0] => MALL1
    )

[1] => SimpleXMLElement Object
    (
        [0] => MALL2
    )

[2] => SimpleXMLElement Object
    (
        [0] => MALL2
    )

)*/

//Example 3:
$array=$info ->xpath('/*/s:Body'); 
echo (string) $array[0]->Response->Result->Success;
//Result is: OK

但是,当然,这不是最好的方法,因为我一次只能得到一个元素,并且无法进行正确的循环。 您将如何以更优雅和正确的方式阅读此 xml 的各种元素? 谢谢。

【问题讨论】:

  • 你能举一个例子来说明你的目标是什么,你是如何尝试获取数据的,以及你想从中得到什么。目前似乎没有具体问题,只是想更轻松地获取数据。
  • 你好@NigelRen,我写了一些关于如何从 xml 中获取数据的示例。问题是,我认为每次只获取 xml 的一个元素进行一百次循环是不正确的或优雅的。就是这样。

标签: php xml parsing namespaces


【解决方案1】:

这是 SOAP,而不仅仅是 XML。最好的选择是使用 SOAP 库。

但是您面临的问题是foreach($info-&gt;xpath('//a:Expenses') as $header) 行将不同的SimpleXMLElement 实例分配给$header 变量,这些变量对您在$info 变量上所做的注册一无所知。您需要在每个SimpleXMLElement 上重复注册。

$info= new SimpleXMLElement($xml);
$info->registerXPathNamespace('s', 'http://example.com');
$info->registerXPathNamespace('a', 'http://www.w3.org/2001/XMLSchema-instance');

foreach($info->xpath('//a:Expenses') as $header)
{
   $header->registerXPathNamespace('a', 'http://www.w3.org/2001/XMLSchema-instance');
   $array = $header->xpath('//a:Expense/a:Store'); 
   print_r($array);
}

或者你开始使用 DOM。在 DOM 中,您创建一个单独的对象来评估 Xpath 表达式。因此,您只需注册一次。此外,您可以使用返回标量值的 Xpath 表达式。

$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMXpath($document);
$xpath->registerXPathNamespace('s', 'http://example.com');
$xpath->registerXPathNamespace('a', 'http://www.w3.org/2001/XMLSchema-instance');

foreach($xpath->evaluate('//a:Expenses/a:Expense') as $expense)
{
   print_r($xpath->evaluate('string(a:Store)', $expense));
}

【讨论】:

    【解决方案2】:

    仅使用 SimpleXML 的更简化的代码版本。基本思想是从包含您之后的所有数据的&lt;Result&gt;(我也使用[0] 表示使用找到的第一个元素)元素开始。然后不再继续使用 XPath,而是获取新定义的 a 命名空间中的所有子元素(使用 children("a", true))。这将允许您在没有任何前缀的情况下访问它们,因此使用标准 SimpleXML 表示法-&gt;...

    $info= new SimpleXMLElement($xml);
    $info->registerXPathNamespace('a', 'http://www.w3.org/2001/XMLSchema-instance');
    
    $result = $info->xpath("//a:Result")[0]->children("a", true);
    //Example 1:
    echo $result->Name.PHP_EOL;
    //Result is: John
    
    //Example 2:
    foreach($result->Expenses->Expense as $header)
    {
        echo (string)$header->Store.PHP_EOL;
    }
    

    哪个输出...

    John
    MALL1
    MALL2
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-21
      • 2012-06-11
      • 1970-01-01
      • 1970-01-01
      • 2010-11-17
      • 2013-04-30
      • 1970-01-01
      相关资源
      最近更新 更多