[PHP] XML Parsen

Pagina: 1
Acties:

Onderwerpen

Vraag


Acties:
  • 0 Henk 'm!

  • ilovetechno
  • Registratie: Oktober 2001
  • Laatst online: 25-09 03:32
Ik maak een API wrapper (REST) om een vrij complexe SOAP service wat makkelijker in gebruik te maken. Hiervoor gebruik ik Slim Framework. Ik ontwikkeld eerst wat classes om deze later te gebruiken binnen het framework. Nu loop ik vast met het verwerken van de response berichten.

Met de onderstaande code genereer ik een request bericht. Dit verstuur ik via Curl.
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Soap_API {

private $relatienummer;

    // This is the construct to start
    public function __construct( $relatienummer ) {
        $this->relatienummer = $relatienummer;
    }

    public function create_request(){
        // Function to reaturn SOAP header and envelope. 

        // Define namespace URI'a
        $xml_soap_uri = 'http://schemas.xxx.nl/soap';
        $xml_soapenv_uri = 'http://schemas.xmlsoap.org/soap/envelope/';
        $xml_body_uri = 'http://schemas.xxx.nl/services/relatieservice';

        //Create header
        $xml = new SimpleXMLElement('<soapenv:Envelope></soapenv:Envelope>', LIBXML_NOERROR, false, 'soapenv', true);
        $xml->addAttribute('xmlns:xmlns:soapenv', $xml_soapenv_uri);
        $xml->addAttribute('xmlns:xmlns:soap', $xml_soap_uri);
        $xml->addAttribute('xmlns:xmlns:rel', 'http://schemas.xxx.nl/services/relatieservice');
        $header = $xml->addChild("soapenv:Header", null, $xml_soapenv_uri );
        $sub_header = $header->addChild("soap:header", null, $xml_soap_uri);
        
        //Set credentials
        $sub_header->addChild('soap:account', 'xxx', $xml_soap_uri);
        $sub_header->addChild('soap:naam', 'xxx', $xml_soap_uri);
        $sub_header->addChild('soap:wachtwoord', 'xxx', $xml_soap_uri);
        $sub_header->addChild('soap:bedrijfsnummer', 'xxx', $xml_soap_uri);
        $sub_header->addChild('soap:tussenpersoonnummer', 'xxx', $xml_soap_uri);

        //Create body
        $body = $xml->addChild("soapenv:Body", null, $xml_soapenv_uri);
        $make = $body->addChild("rel:RelatieLezenViaNummer", null, $xml_body_uri);
        $make = $make->addChild("rel:relatieNummer", $this->relatienummer, $xml_body_uri);
        $xml = $xml->asXML();

    return $xml;
    }
 
}


Vervolgens krijg ik onderstaand bericht terug. Hier wil ik later elementen uit verwijderen, toevoegen en wijzigen om een nieuw request bericht te genereren.Het lukt mij niet om onderstaand bericht (wat waardes verwijderd om dit anonimiseren) op een juiste manier te lezen.

[code=xml]
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<s:RelatieLezenViaNummerResponse
xmlns="http://schemas.xxx.nl/datacatalogus/modellen/modelrelatie"
xmlns:bt="http://schemas.xxx.nl/datacatalogus/basistypes"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:s="http://schemas.xxx.nl/services/xxxservice">
<s:RelatieLezenViaNummerResult>
<adres>Testadres</adres>
<afdelingscode />
<afgiftedatumeersterijbewijs xsi:nil="true" />
<afgiftedatumlegitimatie xsi:nil="true" />
<afgiftedatumrijbewijs>1990-01-01</afgiftedatumrijbewijs>
<ziektekostencode />
<zzpproducten>N</zzpproducten>
<gezinslid>
<burgerservicenummer />
<geboortedatum>2006-01-01</geboortedatum>
<geslacht>M</geslacht>
<idgezinslid>71761</idgezinslid>
<inwonend>1</inwonend>
<naam>Testkind1</naam>
<overlijdensdatum xsi:nil="true" />
<relatieidgezinslid>0</relatieidgezinslid>
<relatienummer>123456</relatienummer>
<roepnaam>Tinus</roepnaam>
<voorletters>T</voorletters>
<voorvoegsels />
</gezinslid>
<gezinslid>
<burgerservicenummer />
<geboortedatum>2005-01-01</geboortedatum>
<geslacht>V</geslacht>
<roepnaam>Tinustwee</roepnaam>
<voorletters>TT</voorletters>
<voorvoegsels />
</gezinslid>
<partner>
<afgiftedatumeersterijbewijs xsi:nil="true" />
<afgiftedatumlegitimatie xsi:nil="true" />
<afgiftedatumrijbewijs xsi:nil="true" />
<bedrijfsspaarregeling>0</bedrijfsspaarregeling>
<beroepscode>0</beroepscode>
<burgerservicenummer>123456</burgerservicenummer>
<emailadres />
<geboortedatum>1979-11-20</geboortedatum>
<geslacht>V</geslacht>
<legitimatienummer />
<naam>Testje</naam>
<nationaliteit>NL</nationaliteit>
<omsberoepscode />
<omsnationaliteit>Nederlandse</omsnationaliteit>
<omstitulatuurcode>Mevrouw</omstitulatuurcode>
<overlijdensdatum xsi:nil="true" />
<relatieidpartner>0</relatieidpartner>
<relatienummer>123456</relatienummer>
<rijbewijscategorie />
<roepnaam />
<soortlegitimatie />
<titel />
<titulatuurcode>2</titulatuurcode>
<voorletters>T.</voorletters>
<voorvoegsels>van</voorvoegsels>
</partner>
<rekeningnummer>
<bicnummer>INGBNL2A</bicnummer>
<tenaamstelling />
<volgnummer>2</volgnummer>
</rekeningnummer>
<werk>
<aardwerkzaamheden />
<emolumenten>0</emolumenten>
<emolumentenperc>0</emolumentenperc>
<extramaanden>0</extramaanden>
</werk>
<zaak>
<aantalpersoneelsleden>0</aantalpersoneelsleden>
<bedrijfscode>0</bedrijfscode>
<bikcode>741230</bikcode>
<kvknummer />
<woonplaatskvk />
</zaak>
</s:RelatieLezenViaNummerResult>
</s:RelatieLezenViaNummerResponse>
</soap:Body>
</soap:Envelope>'
[/code=xml]

Ik wil de elementen teruggeven als return via een aparte functie of class en deze bewerken. Hiervoor moet ik deze natuurlijk eerst kunnen lezen. Daarvoor gebruik ik onderstaande code.

PHP:
1
2
3
4
$xmlxxx = new SimpleXMLElement($xmldoc);
// register namespaces
$xmlxxx->registerXPathNamespace('s', 'http://schemas.xxx.nl/services/relatieservice');
$xmlxxx->registerXPathNamespace('soap', 'http://schemas.xmlsoap.org/soap/envelope/"');

Wanneer ik vervolgens de gegevens probeer op te slaan dan lukt dit niet.
PHP:
1
$items   = $xml->Envelope->Body->RelatieLezenViaNummerResponse->RelatieLezenViaNummerResult;


Wat doe ik hier verkeerd?

Wanneer ik een Xpath query gebruik op onderstaande wijze lijkt het wel te werken.


PHP:
1
2
3
4
foreach ($xmlxxx->xpath('/soap:Envelope/soap:Body/s:RelatieLezenViaNummerResponse/s:RelatieLezenViaNummerResult') as $values)
{
    echo $values "\n";
}


Hoe kan ik hier alleen attributen en waarden uit krijgen om deze later verder te verwerken. De $echo geeft niets terug.

Beste antwoord (via Creepy op 08-12-2016 20:38)


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Holy-moly. Op 't moment dat je SOAP berichten "met de hand" zit samen te stellen en met XML parsers loopt te parsen of met XPath naar nodes gaat lopen zoeken doe je ergens iets ontzettend fout. Al eens gekeken naar de SOAP objecten als SoapClient? (er zijn ook nog wel wat "3rd party" alternatieven overigens). Alle bovenstaande moet in een paar regels code (en een handje vol "DTO classjes") te doen zijn.

[ Voor 48% gewijzigd door RobIII op 08-12-2016 10:45 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij

Alle reacties


Acties:
  • Beste antwoord
  • +6 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Holy-moly. Op 't moment dat je SOAP berichten "met de hand" zit samen te stellen en met XML parsers loopt te parsen of met XPath naar nodes gaat lopen zoeken doe je ergens iets ontzettend fout. Al eens gekeken naar de SOAP objecten als SoapClient? (er zijn ook nog wel wat "3rd party" alternatieven overigens). Alle bovenstaande moet in een paar regels code (en een handje vol "DTO classjes") te doen zijn.

[ Voor 48% gewijzigd door RobIII op 08-12-2016 10:45 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

Verwijderd

^ wat RobIII zegt.

En als je dan toch handmatig de XML/SOAP request in je code zet, dan zou je eventueel kunnen overwegen met simpele placeholders te werken: b.v. ##VOORNAAM## i.p.v. je 'XXX' en dan via een simpele string replace de XML/SOAP request te vullen.

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Verwijderd schreef op donderdag 8 december 2016 @ 10:51:

En als je dan toch handmatig de XML/SOAP request in je code zet, dan zou je eventueel kunnen overwegen met simpele placeholders te werken: b.v. ##VOORNAAM## i.p.v. je 'XXX' en dan via een simpele string replace de XML/SOAP request te vullen.
Neen, neen, driewerf NEEN!
XML "bewerk" je middels DOM/SAX oid. XML is geen "simpele string". Zodra je nu een klant hebt die "Janssen & Janssen" heet ga je al gruwelijk op je bek (ongeldige XML). Sorry, maar dit is een vreselijk advies.

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Verwijderd schreef op donderdag 8 december 2016 @ 10:51:
En als je dan toch handmatig de XML/SOAP request in je code zet, dan zou je eventueel kunnen overwegen met simpele placeholders te werken: b.v. ##VOORNAAM## i.p.v. je 'XXX' en dan via een simpele string replace de XML/SOAP request te vullen.
Is dit een grapje? Wat de *beep* denk je dat er gebeurt als je een naam met een ë als voornaam hebt?

Ik heb me twee keer bij bedrijven heel erg boos moeten maken omdat zij API's aanboden die dit soort dingen deden. Volkomen bizar dat je in 2016 nog met dit soort dingen komt.

https://niels.nu


Acties:
  • +2 Henk 'm!

  • Pizzalucht
  • Registratie: Januari 2011
  • Laatst online: 14:56

Pizzalucht

Snotneus.

Hydra schreef op donderdag 8 december 2016 @ 13:59:
[...]


Is dit een grapje? Wat de *beep* denk je dat er gebeurt als je een naam met een ë als voornaam hebt?

Ik heb me twee keer bij bedrijven heel erg boos moeten maken omdat zij API's aanboden die dit soort dingen deden. Volkomen bizar dat je in 2016 nog met dit soort dingen komt.
Gewoon <![CDATA[]]> gebruiken toch?

* Pizzalucht duikt weg

Acties:
  • 0 Henk 'm!

Verwijderd

ho ho, ik maakte al de kanttekening dat het handmatig definieren van je XML/SOAP request niet ideaal is - verwijzende naar het advies om dat dit beter via DOM of een XML builder/writer te doen.

Wat ik er wél bij had moeten vermelden is dat je dan _op zijn minst_ de variabel waarden XML "safe" moet encoderen zodat een & netjes
code:
1
&amp;
wordt en ook speciale accenten juist worden opgeslagen zonder dat deze botsen met de XML structuur.

Zie ook:
http://php.net/htmlspecialchars

Maar nogmaals, ik gaf al aan dat dit suboptimaal is.

Acties:
  • +2 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Verwijderd schreef op donderdag 8 december 2016 @ 16:38:
ho ho, ik maakte al de kanttekening dat het handmatig definieren van je XML/SOAP request niet ideaal is - verwijzende naar het advies om dat dit beter via DOM of een XML builder/writer te doen.

Wat ik er wél bij had moeten vermelden is dat je dan _op zijn minst_ de variabel waarden XML "safe" moet encoderen zodat een & netjes
code:
1
&amp;
wordt en ook speciale accenten juist worden opgeslagen zonder dat deze botsen met de XML structuur.

Zie ook:
http://php.net/htmlspecialchars

Maar nogmaals, ik gaf al aan dat dit suboptimaal is.
Neeeeeeeeeeeeeeeeeeeeeeeeeeeeeen!

Het heet niet voor niets htmlspecialchars. Los daarvan mis je alle en elke context van de tekst die je zo in het document aan 't "injecteren" bent die een DOM parser wel zal hebben (encoding for one). Er is.... er is zoveel mis met deze methode dat ik niet eens weet waar ik moet beginnen... Ik ga het hier niet nog een keer herhalen dus ik link er maar naar toe: RobIII in "[PHP] XML Parsen"

Los van dit dit "suboptimaal" is en je daarbij en passant iemand een ontzettend slechte gewoonte™ aanleert, is het gewoon een krankzinnige method om met SOAP berichten te werken. Er zijn een crapton aan libraries beschikbaar al deze moeite voor je uit handen nemen en dan hoef je nooit geen XML te zien bij het communiceren met de SOAP Server/Client. Waarom überhaupt moeilijk doen met XML?

edit:
En ja hoor. Beste antwoord... :F :'(

[ Voor 10% gewijzigd door RobIII op 08-12-2016 18:06 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
FML... 8)7
Verwijderd schreef op donderdag 8 december 2016 @ 16:38:
Maar nogmaals, ik gaf al aan dat dit suboptimaal is.
In plaats van jezelf met een shotgun jezelf met een uzi in je voet schieten is verre van optimaal ja...

[ Voor 46% gewijzigd door Hydra op 08-12-2016 18:32 ]

https://niels.nu


Acties:
  • 0 Henk 'm!

  • DJMaze
  • Registratie: Juni 2002
  • Niet online
RobIII schreef op donderdag 8 december 2016 @ 17:52:
Het heet niet voor niets htmlspecialchars.
& #039; (for ENT_HTML401) or & apos; (for ENT_XML1, ENT_XHTML or ENT_HTML5), but only when ENT_QUOTES is set
Zoveel fouten in deze zin :)
Maar "ENT_NOQUOTES | ENT_XML1" is toch echt XML O-)
;w

Maak je niet druk, dat doet de compressor maar


Acties:
  • +2 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 15:11

Creepy

Tactical Espionage Splatterer

Dat "Beste antwoord" heb ik weer uitgezet. Dit zijn normaal gesproken geen zaken om in te grijpen maar dit antwoord als beste markeren kan hier echt niet. Als iemand met een zelfde soort probleem zit wil ik niet dat ze zo'n antwoord gaan gebruiken. Ik heb RobIII's antwoord voorlopig als beste gemarkeerd

[ Voor 10% gewijzigd door Creepy op 08-12-2016 20:39 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

Verwijderd

Creepy schreef op donderdag 8 december 2016 @ 20:37:
[mbr]Dat "Beste antwoord" heb ik weer uitgezet. Dit zijn normaal gesproken geen zaken om in te grijpen maar dit antwoord als beste markeren kan hier echt niet. Als iemand met een zelfde soort probleem zit wil ik niet dat ze zo'n antwoord gaan gebruiken. Ik heb RobIII's antwoord voorlopig als beste gemarkeerd[/]
Helemaal mee eens.
Pagina: 1