使用xpath获取特定部分

时间:2015-04-08 14:31:40

标签: php xml xpath xml-parsing

我有以下xml,我试图抓住以下元素,但不确定它是如何完成的,它靠近底部:

Cashless catering Primary School

任何人都可以通过使用refinement =" Pupil"来建议如何使用xpath获取它。标记/属性?

<?xml version="1.0" encoding="utf-16" standalone="no"?>
<IntegrationExport xmlns="urn:NSCP-Integration-Export-v1">
<Data>
<Citizen messageId="331013" id="43018" authorisingId="1" messageTypeId="1" smartcardId="12345680201327582" serviceId="57" issuer="Primary School">
  <Services>
    <Service application="ISO File Handler" refinement="ISO File Handler" />
    <Service application="CCDA" refinement="CCDA">
      <Item name="SMARTCARDID">12345680201327582</Item>
      <Item name="IIN" />
      <Item name="CARDNO" />
      <Item name="ISSUE">7</Item>
      <Item name="TITLE" />
      <Item name="FORENAME">Jon</Item>
      <Item name="INITIALS" />
      <Item name="SURNAME">Doe</Item>
      <Item name="NAME">Jon Doe</Item>
      <Item name="DOB">2004-11-04 00:00:00</Item>
      <Item name="GENDER">1</Item>
      <Item name="Ethnic Origin">White Other</Item>
      <Item name="Faith" />
      <Item name="SEN / Disability" />
      <Item name="Language" />
      <Item name="DOBVERIFIED">1</Item>
      <Item name="FLAT" />
      <Item name="HOUSE NUMBER/NAME" />
      <Item name="Street" />
      <Item name="Locality" />
      <Item name="Postal Town" />
      <Item name="County" />
      <Item name="POSTCODE" />
      <Item name="LOCAL AUTHORITY" />
      <Item name="RESIDENT">R</Item>
      <Item name="UPRN" />
      <Item name="HOME TEL" />
      <Item name="WORK TEL" />
      <Item name="MOBILE" />
      <Item name="EMAIL" />
      <Item name="Password" />
      <Item name="EXPIRY DATE">2017-09-01 00:00:00</Item>
      <Item name="Reward points">90</Item>
      <Item name="UPN">E301207408111</Item>
      <Item name="ParentPay ID">4292111</Item>
      <Item name="PayPoint Account No" />
      <Item name="YEARGROUP">3</Item>
      <Item name="FORMNAME">RED</Item>
      <Item name="Acknowledgement" />
      <Item name="USERID" />
      <Item name="REWARDS DATE" />
      <Item name="BARCODE">00100048123</Item>
      <Item name="MEMBER ID" />
      <Item name="LEISURECODE" />
      <Item name="LEISUREDATE" />
    </Service>
    <Service application="Special Needs" refinement="Special Needs">
      <Item name="CUSTOM MESSAGE">Placeholder message for special needs application.</Item>
      <Item name="SCREEN COLOUR">00</Item>
      <Item name="FONT">00</Item>
      <Item name="CHARACTER SIZE">00</Item>
      <Item name="SPEECH OUTPUT">00</Item>
    </Service>
    <Service application="Cashless catering Primary School" refinement="Pupil" />
    <Service application="Splash" refinement="Splash">
      <Item name="USERNAME" />
      <Item name="INITIAL PASSWORD" />
    </Service>
  </Services>
</Citizen>

代码

$endpoint = "http://111.222.11.200/someUrl.asmx?WSDL";
$client = new SoapClient($endpoint, array('trace' => 1));
$xml = $client->GetCitizenData($arrValues);
$xml = (string)$xml->GetCitizenDataResult;

$xml = preg_replace('/(<\?xml[^?]+?)utf-16/i', '$1utf-8', $xml);
$xml_element = simplexml_load_string($xml);

$nodes = $xml_element->xpath('/Citizen/Services/Service[@refinement="Pupil"]/@application');

当我转储节点数组时,我得到以下内容:

SimpleXMLElement Object ( [@attributes] => Array ( [application] => Cashless catering Primary School ) ) 

2 个答案:

答案 0 :(得分:2)

所以,最后我们已经确定了 1 你已经得到了正确的结果,就XPath而言;路径表达式检索正确的节点。

唯一的困难是评估路径表达式会返回数组。当整个数组被转储时,你自然会得到比想要的字符串本身更多的东西。使用

var_dump($nodes[application]);

只会转储此数组中的第一项:

string(32) "Cashless catering Primary School"

使用reset()会做类似的事情:

<?php
$array = array( application => 'Cashless catering Primary School');
echo reset($array);
?>

array_values($array)[0]一样。


但请注意,在许多情况下不鼓励使用PHP和Java的SimpleXML库,因为它们的行为可能令人惊讶。在您的特定情况下,可以原谅期望像

这样的XPath表达式
//Citizen

不会返回任何内容,因为这些元素位于默认命名空间中。通常,默认名称空间需要在PHP代码中重新声明,并且可用于XPath引擎。但是SimpleXML忽略了默认名称空间 - 这实际上是“不那么简单”。


1 这应该教你一个关于写好问题的教训。对于您将来的问题,请务必立即包含所有相关信息。

答案 1 :(得分:1)

假设您已为命名空间x注册了别名urn:NSCP-Integration-Export-v1,则只需抓取属性&#34;应用&#34;:

//x:Citizen/x:Services/x:Service[@refinement='Pupil']/@application

修改

如果您无法使用命名空间,则可以使用命名空间不可知的本地名称()&#39;。请注意,我假设您在同一个树中只有一种CitizenService,这似乎是合理的,因为您的示例文档引用了一个命名空间。

//*[local-name()='Citizen']//*[local-name()='Service' and @refinement='Pupil']/@application