[PHP / SimpleXML] Nodes met '-' en '.' erin benaderen *

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Dag mensen,

ik ben momenteel aan het kijken wat de beste manier is om een xml-file uit te lezen.
Ik kom er echter niet goed uit en google geeft met niet de gewenste resultaten.
Via DOM heb ik problemen met het lezen van attributes..

en via simple_xml krijg ik ook niet alles uitgelezen.

Ik krijg onderstaande xmlfile doorgestuurd vanuit de klant:

XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" ?>


<elements>
<artikel>
    <head>
        <title>Title van het document</title> 
        <docdata>
            <doc-id id-string="09853098543" />
                        <doc.file>bestand</doc.file> 

        </docdata>

    </head>
    <body>
        <bodycontent>
            <p>lorem ipsum</p>
        </bodycontent>
    </body>
</artikel>
</elements>



Die probeer ik vervolgens uit te lezen:

PHP:
1
2
3
4
5
6
7
8
9
10
    $xmldoc = simplexml_load_file('xml.xml');

        foreach ($xmldoc->artikel as $element) {
            echo 'title: '. $element->head->title.'<br />';

            echo 'id-string: '. $element->head->doc-id['id-string'].'<br />';
            
            echo 'body: '. $element->body->bodycontent;
            
        }


Ik krijg echter die id-string niet ingeladen omdat php 'doc-id' niet accepteert vanwege het streepje.
Dat geldt ook voor de 'doc.file' !
Bovendien krijg ik ook de lorem ipsum niet te zien omdat de htmltags verstoren werken.
Ik zoek me echt suf maar kom er helaas niet uit.

Iemand een tip?

Acties:
  • 0 Henk 'm!

  • Alex)
  • Registratie: Juni 2003
  • Laatst online: 21-08 11:20
Doe eens een print_r op je $xmldoc, en kijk eens welke structuur je krijgt :-)

We are shaping the future


Acties:
  • 0 Henk 'm!

  • Patriot
  • Registratie: December 2004
  • Laatst online: 16-09 13:49

Patriot

Fulltime #whatpulsert

Je kunt het streepje en de punt toch gewoon even vervangen voor iets anders? Desnoods in hun geheel weghalen. Dat moet je toch wel lukken.

Die andere is wat dat betreft lastiger. Je kunt, als je zeker weet dat de sluittag van de bodycontent-tag niet in de tekst voor zal komen met een reguliere expressie wel zorgen dat alles in die tag even door htmlentities() gehaald wordt.

Acties:
  • 0 Henk 'm!

  • Noork
  • Registratie: Juni 2001
  • Niet online
Is het gebruik van een dash en een punt wel valide XML? Zo nee, dan kan ik me voorstellen dat simplexml er niet mee om kan gaan. Je zou kunnen proberen door vooraf aan het inlezen b.v. een copy te maken van het bestand en de elementen eenvoudigweg te replacen door andere.

@hieronder: Dank voor de opheldering van de XML specificaties. Ik zat ook al te zoeken, maar kon het helaas niet vinden. Verder zeg ik niet dat mijn oplossing 'mooi' is, ben het met je eens dat het een 'gore' oplossing is.

[ Voor 29% gewijzigd door Noork op 08-09-2008 09:57 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Noork schreef op maandag 08 september 2008 @ 01:35:
Is het gebruik van een dash en een punt wel valide XML?
Ja en ja.
Zo nee, dan kan ik me voorstellen dat simplexml er niet mee om kan gaan. Je zou kunnen proberen door vooraf aan het inlezen b.v. een copy te maken van het bestand en de elementen eenvoudigweg te replacen door andere.
Het is een gore oplossing, maar hij werkt wel. Goor omdat je eigenlijk geen string operaties op XML zou moeten doen.

SimpleXML heeft gewoon zo zijn beperkingen. Het is ook (nog) geen volledige namespace aware parser.

[ Voor 7% gewijzigd door Verwijderd op 08-09-2008 07:44 ]


Acties:
  • 0 Henk 'm!

  • Noork
  • Registratie: Juni 2001
  • Niet online
Ik vind dit trouwens op internet:
If you want to access an element that has a dash in its name, (as is common with the XML documents provided by the Library of Congress, as well as the NWS) you will need to handle it a little bit differently.

You can either use XPATH, which works fine, but will return an array of results every time, even if there is a single result.
eg.
$xml->xpath('/data/time-layout/start-valid-time'}

You can also choose just to encapsulate the element names containing a dash:
$xml->data->{'time-layout'}->{'start-valid-time'} Bron: http://algorytmy.pl/doc/php/ref.simplexml.php
Je zou het dus met Xpath kunnen proberen.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik heb de oplossing van Noork even getest en deze lijkt vooralsnog te werken voor wat betreft de dash en dot.

PHP:
1
$element->head->docdata->{'doc-id'}{'id-string'}
Patriot schreef op maandag 08 september 2008 @ 01:34:
Die andere is wat dat betreft lastiger. Je kunt, als je zeker weet dat de sluittag van de bodycontent-tag niet in de tekst voor zal komen met een reguliere expressie wel zorgen dat alles in die tag even door htmlentities() gehaald wordt.
Een print_r op de bodycontent levert me het volgende:

PHP:
1
SimpleXMLElement Object ( [p] => Array ( [0] => een hoop tekst [1] => Nog meer tekst [2] => En nog meer tekst )   ) body: 1


Hoe zou ik dan volgens jou te werk moeten gaan?
Zo??
PHP:
1
2
3
foreach ($element->body->bodycontent as $tempelement) {
     htmlentities($tempelement);
}

Acties:
  • 0 Henk 'm!

  • Noork
  • Registratie: Juni 2001
  • Niet online
Verwijderd schreef op maandag 08 september 2008 @ 10:54:
Een print_r op de bodycontent levert me het volgende:

PHP:
1
SimpleXMLElement Object ( [p] => Array ( [0] => een hoop tekst [1] => Nog meer tekst [2] => En nog meer tekst )   ) body: 1


Hoe zou ik dan volgens jou te werk moeten gaan?
Zo??
PHP:
1
2
3
foreach ($element->body->bodycontent as $tempelement) {
     htmlentities($tempelement);
}
Volgens mij gaat het niet werken, omdat het een array is. Lijkt me dat SimpleXML hier gewoonweg niet zo geschikt voor is. Kun je dit niet oplossen met gewone PHP substrings of reguliere expressies?

Acties:
  • 0 Henk 'm!

  • tonyisgaaf
  • Registratie: November 2000
  • Niet online
<p> is toch gewoon een node in de XML-tree? Jíj weet dat dat een tekstelement voor HTML uitvoer is, maar dat weet de XML parser natuurlijk niet, díe ziet simpelweg een node "p" met daarin een textnode "Lorem ipsum". Dus wanneer je de HTML weer wilt bouwen zul jíj het onderscheid moeten maken tussen nodes waarvan je letterlijk de naam wil laten terugkomen in de HTML (zoals p) of waarvan je alleen de inhoud wilt weten. Uiteindelijk zijn alleen de textnodes geschikt om direct in de uitvoer te gebruiken, de andere nodes zijn objecten of arrays.

NL Weerradar widget Euro Stocks widget Brandstofprijzen widget voor 's Dashboard


Acties:
  • 0 Henk 'm!

Verwijderd

Haal de boel gewoon door een goede XSLT transformator. Dan ben je ook van dat gedoe af.

Acties:
  • 0 Henk 'm!

  • Noork
  • Registratie: Juni 2001
  • Niet online
Ik ben even in de simpleXML documentatie gedoken. Volgens mij kun je de html ophalen met asXML()

Zie: http://nl3.php.net/manual...mplexml-element-asXML.php

Acties:
  • 0 Henk 'm!

  • eamelink
  • Registratie: Juni 2001
  • Niet online

eamelink

Droptikkels

De PHP lexer snapt alleen simpele propertynamen, als je ingewikkelde wilt gebruiken moet je ze even encapsulaten:

PHP:
1
2
$a =  new stdClass();
$a->{'#@$%543_-'} = 10; // Dit werkt dus.


In jouw voorbeeld moet je regel 6 dus vervangen door :

PHP:
1
echo 'id-string: '. $element->head->docdata->{'doc-id'}['id-string'].'<br />';

Je was trouwens ook de ->docdata hierin vergeten.

Het probleem met de bodycontent kan je oplossen door de inhoud ervan in een CDATA blok te zetten, want het moet immers niet geparst worden :)

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
eamelink schreef op maandag 08 september 2008 @ 17:20:
In jouw voorbeeld moet je regel 6 dus vervangen door :

PHP:
1
echo 'id-string: '. $element->head->docdata->{'doc-id'}['id-string'].'<br />';
Klopt, dat geef ik hierboven ook al aan.. ['id-string'] moet {'id-string'} zijn trouwens.. anders werkt t niet.
eamelink schreef op maandag 08 september 2008 @ 17:20:

Het probleem met de bodycontent kan je oplossen door de inhoud ervan in een CDATA blok te zetten, want het moet immers niet geparst worden :)
Dan moet ik dus de aanbieder van de xml vragen dit in CDATA te zetten?
Of kan ik dat bij het uitlezen van de xml ook doen?
Dat laatste krijg ik nl. niet gevonden.

Onderstaande kan ik prima uitlezen:

XML:
1
2
3
<bodycontent>
<![CDATA[<p>lorem ipsum.</p><p>lorem ipsum.</p><p>lorem ipsum.</p>]]>
</bodycontent>

[ Voor 8% gewijzigd door Verwijderd op 09-09-2008 16:58 ]


Acties:
  • 0 Henk 'm!

  • Noork
  • Registratie: Juni 2001
  • Niet online
Verwijderd schreef op dinsdag 09 september 2008 @ 16:55:
Dan moet ik dus de aanbieder van de xml vragen dit in CDATA te zetten?
Of kan ik dat bij het uitlezen van de xml ook doen?
Dat laatste krijg ik nl. niet gevonden.
Je kan van alles doen. Vragen of de aanbieder het in CDATA zet. Zelf toevoegen aan de XML file (met str_replace o.i.d.). Of even kijken naar mijn vorige post (de asXML() functie, dat lijkt me veelbelovend)

Verwijderd

Topicstarter
Noork schreef op dinsdag 09 september 2008 @ 16:59:
Of even kijken naar mijn vorige post (de asXML() functie, dat lijkt me veelbelovend)
Heb er nog even naar gekeken... en werkt!
In dit geval zit er in de bodycontent nog een extra aantal nodes.. waaronder <media>text</media>
Die vis ik eruit met:

PHP:
1
2
3
4
5
6
// onderstaande levert me de volledige inhoud van bodycontent op;
// dit wordt niet geprint maar staat wel tussen je code (view source)
$bodycontent = $element->body->bodycontent->asXML(); 

// om het wat netter te maken pluk ik alle overbodige nodes ook nog uit de bodycontent
$bodycontent = ereg_replace('<media>(.*)</media>', '', $bodycontent);


dank voor de hulp!

[ Voor 17% gewijzigd door Verwijderd op 10-09-2008 23:12 ]


  • tonyisgaaf
  • Registratie: November 2000
  • Niet online
Verwijderd schreef op woensdag 10 september 2008 @ 23:11:
[...]


Heb er nog even naar gekeken... en werkt!
In dit geval zit er in de bodycontent nog een extra aantal nodes.. waaronder <media>text</media>
Die vis ik eruit met:

PHP:
1
2
// om het wat netter te maken pluk ik alle overbodige nodes ook nog uit de bodycontent
$bodycontent = ereg_replace('<media>(.*)</media>', '', $bodycontent);


dank voor de hulp!
Ik zou de match dan nog non-greedy maken:
<media>.*?</media>
Stel dat je meerdere <media> nodes hebt, dan wordt alles tussen de eerste <media> en de laatste </media> verwijdert, ook wanneer er nodes tussenstaan die je wilt bewaren. In het non-greedy geval dus niet, dan wordt alles tussen <media> en de eerstvolgende </media> gematcht.

[ Voor 6% gewijzigd door tonyisgaaf op 11-09-2008 17:36 ]

NL Weerradar widget Euro Stocks widget Brandstofprijzen widget voor 's Dashboard


Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
NB: Anno 2008 moet jeJe moet altijd de preg_* functies kiezen ipv de ereg_* functies.

edit:
:Y) (en preg is meestal sneller)

[ Voor 27% gewijzigd door Voutloos op 12-09-2008 08:02 ]

{signature}


Acties:
  • 0 Henk 'm!

Verwijderd

Voutloos schreef op vrijdag 12 september 2008 @ 07:57:
NB: Anno 2008 moet je gewoon altijd de preg_* functies kiezen ipv de ereg_* functies.
Dat anno 2008 had je weg mogen laten. De ereg* functies zijn altijd al minder handig en minder krachtig geweest dan de perl compatible expressies. :)

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ola,

ik ben dankzij alle tips lekker bezig... ik krijg de xml files prima ingelezen om ze vervolgens in de database te plaatsen.

Nu krijg ik echter van mijn opdrachtgever xml-bestanden van ettelijke 100-en mb's groot.
Dit ga ik niet met een simpel upload scriptje op mijn server zetten om vervolgens uit te lezen 8)7

Mijn idee is dus om deze grote files op te splitsen in kleinere behapbare xml-bestandjes.
Nu is mijn vraag echter... hoe?
Is daarvoor bestaande software beschikbaar waar ik op basis van de <artikel>-node (of liefst meerdere) kan splitsen in meerdere bestanden? Ik heb al veel gegoogled maar vooralsnog krijg ik niet gevonden wat ik zoek.

Of kan ik dit beter doen door op mijn pc'tje apache/php5 te installeren en het toch via php uit te lezen? Heeft dat laatste enige kans van slagen?

Acties:
  • 0 Henk 'm!

  • BHR
  • Registratie: Februari 2002
  • Laatst online: 17-09 21:58

BHR

Gebruik een pull parser / stax. Op deze manier hoef je niet 100Mb in te laden zoals bij dom, maar loop je eenmalig door het hele document heen. Tijdens het doorlopen verwerk je de elementen die je nodig hebt.

Ik zie dat http://nl3.php.net/manual/en/intro.xmlreader.php een pull parser is?!

No amount of key presses will shut off the Random Bug Generator

Pagina: 1