Использование xpath для захвата определенного раздела

72
10

У меня есть следующий xml, и я пытаюсь захватить следующий элемент, но не знаю, как это делается, что находится внизу:

Cashless catering Primary School

Может ли кто-нибудь предложить, как это сделать, используя 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 ) ) 

спросил(а) 2015-04-08T17:31:00+03:00 5 лет, 6 месяцев назад
1
Решение
70

Итак, наконец, мы разработали 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].

Но обратите внимание, что использование библиотек SimpleXML для PHP и Java не рекомендуется во многих контекстах, потому что их поведение может быть неожиданным. В вашем конкретном случае можно простить, чтобы ожидать, что выражение XPath

//Citizen

ничего не вернет, поскольку эти элементы находятся в пространстве имен по умолчанию. Обычно пространства имен по умолчанию должны быть переопределены в PHP-коде и доступны для механизма XPath. Но SimpleXML игнорирует пространства имен по умолчанию, что на самом деле "не так просто".

1 Это должно научить вас урок о написании хороших вопросов. Для ваших будущих вопросов обязательно включите всю соответствующую информацию сразу.

ответил(а) 2015-04-08T18:01:00+03:00 5 лет, 6 месяцев назад
58

Предполагая, что вы зарегистрировали псевдоним x для пространства имен urn:NSCP-Integration-Export-v1, чтобы захватить только атрибут "приложение":

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

редактировать

Если вы не можете использовать пространства имен, вы можете использовать агностическое пространство имен "local-name()". Обратите внимание, что я предполагаю, что у вас есть только один тип Citizen или Service в одном и том же дереве, что кажется разумным, поскольку ваш образец документа ссылается на одно пространство имен.

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

ответил(а) 2015-04-08T17:36:00+03:00 5 лет, 6 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема