从多个 XML 行中提取数据

Posted

技术标签:

【中文标题】从多个 XML 行中提取数据【英文标题】:Extract Data off multiple XML row 【发布时间】:2015-03-26 15:18:20 【问题描述】:

我有一个非常奇怪的 XML 响应,我需要提取它的数据。我需要在“value”属性中获取数据,但我需要根据它们的“key”属性来选择它们。

看起来是这样的

       <phone>
       2125556666
       </phone>
       <State>
       ny
       </State>
       <Response>
           <data key="Supported" value="Yes"/>
           <data key="Host" value="Remote"/>
           <data key="WholeProductList">
               <data key="Product" value="a-z44"/>
               <data key="Product" value="c-k99"/>
               <data key="Product" value="e-b089"/>
               <data key="Product" value="z-p00"/>
               <data key="Product" value="r-333"/>
               <data key="Product" value="t-RS232"/>
               <data key="Product" value="4-lve"/>
               <data key="Product" value="Shutdown"/>
           </data>
       </Response>

在我目前拥有的 php

$xmltmp = new DomDocument;
$xmltmp->loadXml($response);
$phone = $xmlresponse->getElementsByTagName('phone')->item(0)->nodeValue;
$state = $xmlresponse->getElementsByTagName('state')->item(0)->nodeValue;
echo $phone;
echo $state;

这当前输出电话号码和状态。它工作正常。

现在我需要知道“支持”键的值是“是”还是“否”,如果是,我需要获取所有“产品”。我有点卡住了,因为我很难做出 foreach 语句然后检查“key”属性值。

谢谢!

【问题讨论】:

对它使用 XPath 查询;例如将Response/data@key 设置为变量并检查是否为“是”。 感谢您的快速响应。你认为有办法避免 XPath 还是强制的? DomDocument 类中可能有内置方法?? 如果没有 XPath,您可能需要循环所有 &lt;data&gt; 元素 - 使用 XPath 会更整洁。 【参考方案1】:

您的 XML 无效。 XML 文档总是需要一个文档元素节点。

例子:

<root> 
  <phone>2125556666</phone>
  <State>ny</State>
    <Response>
      <data key="Supported" value="Yes"/>
      ...
    </data>
  </Response>
</root>

从 DOM 获取数据的最简单方法是 XPath。在由DOMXPath 类和ext/dom 的一部分提供的PHP 中。 DOMXPath::evaluate() 允许您从 DOM 文档中获取节点列表或标量值。

$dom = new DOMDocument;
$dom->loadXml($xml);
$xpath = new DOMXPath($dom);

$phone = $xpath->evaluate('string(/*/phone)');
$state = $xpath->evaluate('string(/*/State)');
var_dump($phone, $state);

输出:

string(10) "2125556666"
string(2) "ny"

/*/phone 这样的表达式会选择文档元素内的所有phone 元素子节点。 string(/*/phone) 将找到的第一个节点转换为字符串并返回。如果没有找到节点,它将返回一个空字符串。

受支持状态的 XPath 表达式稍微复杂一些。节点条件在[] 中提供。可以直接在 XPath 中比较结果。返回值将是一个布尔值。

$supported = $xpath->evaluate('/*/Response/data[@key="Supported"]/@value = "Yes"');
var_dump($supported);

输出:

bool(true)

如果表达式返回一个节点列表,您可以使用 foreach() 对其进行迭代。

$nodes = $xpath->evaluate(
  '/*/Response/data[@key="WholeProductList"]/data[@key="Product"]/@value'
);
$products = [];
foreach ($nodes as $attributeNode) 
  $products[] = $attributeNode->value;

var_dump($products);

输出:

array(8) 
  [0]=>
  string(5) "a-z44"
  [1]=>
  string(5) "c-k99"
  [2]=>
  string(6) "e-b089"
  [3]=>
  string(5) "z-p00"
  [4]=>
  string(5) "r-333"
  [5]=>
  string(7) "t-RS232"
  [6]=>
  string(5) "4-lve"
  [7]=>
  string(8) "Shutdown"

【讨论】:

哦,哇,这是一个如此完整的答案,我无法不将其标记为已接受。非常感谢您花时间写这篇文章,非常感谢您为此付出的努力! 您好!经过大量测试,我意识到$product = []; 不起作用。我只是做$product = array();,它工作得很好。也许[] 可以用另一种语言调用数组?? 你有一个旧的php版本,当前的php支持替代数组语法。 啊——我假设它只是一个 XML sn-p 而不是整个文档;很好的答案:)【参考方案2】:

这不会“按原样”工作,因为我不知道 XML 文档的实际结构是什么,但简而言之,您可以将 XML 节点映射到 XPath,例如 //root/node/child_node/@attribute 等等。

它还应该有一些健全的(非空)类型检查。

$xmltmp = new DomDocument;
$xmltmp->loadXml($response);
$xQuery = new DOMXPath($xmltmp);

//not sure what your root node is so the query path is probably wrong
$supported = $xQuery->query('/Response/data[@key="Supported"]/@value')->value;

你也可以替换:

$phone = $xmlresponse->getElementsByTagName('phone')->item(0)->nodeValue;
$state = $xmlresponse->getElementsByTagName('state')->item(0)->nodeValue;

使用类似的东西(同样 - 如果没有 XML 文档的完整结构,路径本身可能不太正确):

$phone = $xQuery->query('/phone')->item(0)->nodeValue;
$state = $xQuery->query('/State')->item(0)->nodeValue;

【讨论】:

以上是关于从多个 XML 行中提取数据的主要内容,如果未能解决你的问题,请参考以下文章

从多个 XML 节点中提取值 [重复]

如何从具有由“|”分隔的字段的行中提取数据C++中的字符?

从 Clob 列中提取 XML 标记值,在 Oracle 中具有多个具有相同名称的标记

从Excel中的行中提取唯一值

如何在 SQL 中提取特定的多个文本?

从 UDF 内的 Spark SQL 行中提取嵌套数组