Zabs
Zabs

Reputation: 14142

Using xpath to grab a particular section

I have the following xml and I'm trying to grab the following element but not sure how it is done that is near the bottom:

Cashless catering Primary School

Can anyone suggest how to grab this using xpath by using the refinement="Pupil" tag/attribute?

<?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>

Code

$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');

When I dump the nodes array I get the following:

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

Upvotes: 0

Views: 105

Answers (2)

Mathias M&#252;ller
Mathias M&#252;ller

Reputation: 22617

So, finally we have worked out1 that you were already getting the correct results, as far as XPath is concerned; your path expression retrieves the correct node.

The only difficulty was that evaluating the path expression returns an array. When the whole array is dumped, you naturally get back more than the wanted string itself. Using

var_dump($nodes[application]);

will only dump the first item in this array:

string(32) "Cashless catering Primary School"

Using reset() would do something similar:

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

as would array_values($array)[0].


But note that using the SimpleXML libraries of PHP and Java is discouraged in many contexts, because their behaviour can be surprising. In your specific case, one could be forgiven to expect that an XPath expression like

//Citizen

would not return anything, since those elements are in a default namespace. Usually, default namespaces need to be redeclared in PHP code, and made available to the XPath engine. But SimpleXML ignores default namespaces - which is "not so simple", really.


1 This should teach you a lesson about writing good questions. For your future questions, please make sure to include all relevant information right away.

Upvotes: 2

StuartLC
StuartLC

Reputation: 107297

Assuming you've registered an alias x for namespace urn:NSCP-Integration-Export-v1, to grab just the attribute "application":

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

Edit

If you aren't able to utlilize namespaces, you can use the namespace agnostic 'local-name()'. Note that I'm assuming that you have only one type of Citizen or Service in the same tree, which seems reasonable as your sample document references one namespace.

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

Upvotes: 1

Related Questions