XML ontleden. Items overslaan die je niet nodig hebt

Het ontleden van XML betekent in wezen het doorlopen van een XML-document en het retourneren van de juiste gegevens. Hoewel een toenemend aantal webservices gegevens in JSON-indeling retourneert, gebruiken de meeste nog steeds XML, dus het is belangrijk om XML-parsing onder de knie te krijgen als u het volledige scala aan beschikbare API's wilt gebruiken.

De extensie gebruiken SimpleXML in PHP, dat is toegevoegd in PHP 5.0, is het werken met XML heel eenvoudig en ongecompliceerd. In dit artikel laat ik je zien hoe je dit doet.

Basisprincipes van gebruik

Laten we beginnen met het volgende voorbeeld: talen.xml:


>

> 1972>
> Dennis Ritchie >
>

> 1995>
> Rasmus Lerdorf >
>

> 1995>
> James gansje >
>
>

Dit XML-document bevat een lijst met programmeertalen met wat informatie over elke taal: het jaar van implementatie en de naam van de maker.

De eerste stap is om de XML te laden met behulp van functies ofwel: simplexml_load_file () of simplexml_load_string ()... Zoals de naam van de functies suggereert, laadt de eerste XML uit een bestand en de laatste laadt XML uit een string.

Beide functies lezen de volledige DOM-boom in het geheugen en retourneren een object SimpleXMLElement... In het bovenstaande voorbeeld wordt het object opgeslagen in de $ languages-variabele. U kunt functies gebruiken var_dump () of print_r () om details over het geretourneerde object te krijgen, als je wilt.

SimpleXMLElement-object
[taal] => Matrix
[0] => SimpleXMLElement-object
[@ attributen] => Matrix
[naam] => C
[verscheen] => 1972
[maker] => Dennis Ritchie
[1] => SimpleXMLElement-object
[@ attributen] => Matrix
[naam] => PHP
[verscheen] => 1995
[maker] => Rasmus Lerdorf
[2] => SimpleXMLElement-object
[@ attributen] => Matrix
[naam] => Java
[verscheen] => 1995
[maker] => James Gosling
)
)

Deze XML bevat het root-element talen, waarbinnen er drie elementen zijn lang. Elk element van de array komt overeen met een element lang in het XML-document.

U kunt toegang krijgen tot de eigenschappen van een object met behulp van de operator -> ... $ talen-> lang zal u bijvoorbeeld een SimpleXMLElement-object retourneren dat overeenkomt met het eerste element lang... Dit object bevat twee eigenschappen: verschenen en schepper.

$ talen -> lang [0] -> verscheen;
$ talen -> lang [0] -> maker;

Het is heel eenvoudig om een ​​lijst met talen weer te geven en hun eigenschappen te tonen met behulp van een standaardlus zoals: foreach.

foreach ($ talen -> lang als $ lang) (
printf (
"" ,
$ lang ["naam"],
$ lang -> verscheen,
$ lang -> maker
) ;
}

Merk op hoe ik toegang kreeg tot de attribuutnaam van het lang-element om de taalnaam te krijgen. Op deze manier hebt u toegang tot elk attribuut van een element dat wordt weergegeven als een SimpleXMLElement-object.

Werken met naamruimten

Als je met de XML van verschillende webservices werkt, kom je meer dan eens elementnaamruimten tegen. Laten we onze veranderen talen.xml om een ​​voorbeeld te tonen van het gebruik van de naamruimte:



xmlns: dc =>

> 1972>
> Dennis Ritchie >
>

> 1995>
> Rasmus Lerdorf >
>

> 1995>
> James gansje >
>
>

Nu het element Schepper geplaatst in de naamruimte dc die verwijst naar http://purl.org/dc/elements/1.1/. Als u de taalmakers probeert af te drukken met onze vorige code, dan zal dit niet werken. Om de naamruimten van elementen te lezen, moet u een van de volgende benaderingen gebruiken.

De eerste benadering is om URI's rechtstreeks in code te gebruiken bij het verwijzen naar de naamruimte van het element. Het volgende voorbeeld laat zien hoe dit wordt gedaan:

$ dc = $ talen -> lang [1] -> kinderen ( "http://purl.org/dc/elements/1.1/") ;
echo $ dc -> schepper;

Methode kinderen () neemt een naamruimte en retourneert onderliggende elementen die beginnen met een voorvoegsel. Er zijn twee argumenten nodig, het eerste is een XML-naamruimte en het tweede optionele argument is standaard: vals... Als het tweede argument TRUE is, wordt de naamruimte behandeld als een prefix. Indien ONWAAR, wordt de naamruimte behandeld als een URL-naamruimte.

De tweede benadering is om de URI-namen uit het document te lezen en deze te gebruiken bij het verwijzen naar de naamruimte van het element. Dit is eigenlijk de beste manier om toegang te krijgen tot de elementen, omdat u de URI niet hard hoeft te coderen.

$ namespaces = $ talen -> getNamespaces (true);
$ dc = $ talen -> lang [1] -> kinderen ($ naamruimten ["dc"]);

echo $ dc -> schepper;

Methode GetNamespaces () retourneert een reeks voorvoegselnamen en de bijbehorende URI's. Er is een extra parameter voor nodig, die standaard is vals... Als je het instelt als waar dan retourneert deze methode de namen die worden gebruikt in de bovenliggende en onderliggende knooppunten. Anders vindt het naamruimten die alleen in het bovenliggende knooppunt worden gebruikt.

U kunt nu als volgt door de lijst met talen stappen:

$ talen = simplexml_load_file ("talen.xml");
$ ns = $ talen -> getNamespaces (true);

foreach ($ talen -> lang als $ lang) (
$ dc = $ lang -> kinderen ($ ns ["dc"]);
printf (
"

% s verscheen in% d en is gemaakt door% s.

" ,
$ lang ["naam"],
$ lang -> verscheen,
$ dc -> maker
) ;
}

Casestudy - Een YouTube-videokanaal ontleden

Laten we eens kijken naar een voorbeeld dat een RSS-feed van een YouTube-kanaal ontvangt en links naar alle video's ervan weergeeft. Hiervoor dient u contact op te nemen met het volgende adres:

http://gdata.youtube.com/feeds/api/users/xxx/uploads

De URL retourneert een lijst met de nieuwste video's van het opgegeven kanaal in XML-indeling. We zullen de XML ontleden en de volgende informatie krijgen voor elke video:

  • Link naar video
  • Miniatuur
  • Naam

We beginnen met het zoeken en laden van de XML:

$ kanaal = "Kanaalnaam";
$ url = "http://gdata.youtube.com/feeds/api/users/"... $ kanaal. "/ uploadt";
$ xml = file_get_contents ($ url);

$ feed = simplexml_load_string ($ xml);
$ ns = $ feed -> getNameSpaces (waar);

Als je naar de XML-feed kijkt, kun je zien dat er verschillende elementen in zitten entiteit, die elk gedetailleerde informatie over een specifieke video van een kanaal opslaan. Maar we gebruiken alleen thumbnails, video-URL en titel. Deze drie elementen zijn afstammelingen van het element groep die op zijn beurt een kind is van binnenkomst:

>

>



Titel ... >

>

>

We gaan gewoon door alle elementen. binnenkomst, en voor elk van hen extraheren we de nodige informatie. Let daar op speler, miniatuur en titel bevinden zich in de medianaamruimte. Daarom moeten we doorgaan zoals in het vorige voorbeeld. We halen de namen uit het document en gebruiken de naamruimte bij het verwijzen naar de elementen.

foreach ($ feed -> invoer als $ invoer) (
$ groep = $ invoer -> kinderen ($ ns ["media"]);
$ groep = $ groep -> groep;
$ thumbnail_attrs = $ group -> thumbnail [1] -> attributen ();
$ afbeelding = $ thumbnail_attrs ["url"];
$ speler = $ groep -> speler -> attributen ();
$ link = $ speler ["url"];
$ titel = $ groep -> titel;
printf ( "

" ,
$ speler, $ afbeelding, $ titel);
}

Gevolgtrekking

Nu je weet hoe je het moet gebruiken SimpleXML voor het ontleden van XML-gegevens kunt u uw vaardigheden verbeteren door verschillende XML-feeds met verschillende API's te ontleden. Maar het is belangrijk om in gedachten te houden dat SimpleXML de hele DOM in het geheugen leest, dus als u een grote dataset aan het parseren bent, kan het zijn dat u onvoldoende geheugen heeft. Lees de documentatie voor meer informatie over SimpleXML.


Als u vragen heeft, raden we u aan onze

Nu gaan we het werken met XML bestuderen. XML is een formaat voor het uitwisselen van gegevens tussen sites. Het lijkt erg op HTML, behalve dat XML zijn eigen tags en attributen toestaat.

Waarom heb je XML nodig bij het parseren? Soms gebeurt het zo dat de site die je moet ontleden een API heeft waarmee je zonder al te veel moeite kunt krijgen wat je wilt. Daarom, slechts een tip - controleer voordat u de site analyseert of deze een API heeft.

Wat is een API? Dit is een set van functies waarmee u een verzoek naar deze site kunt sturen en het gewenste antwoord kunt krijgen. Dit antwoord komt meestal in XML-formaat. Dus laten we het gaan bestuderen.

Werken met XML in PHP

Stel je hebt XML. Het kan in een string staan, in een bestand worden opgeslagen of op verzoek worden teruggestuurd naar een specifieke URL.

Laat de XML worden opgeslagen in een string. In dit geval moet u vanaf deze regel een object maken met nieuw SimpleXMLElement:

$ str = " Kolya 25 1000 "; $ xml = nieuw SimpleXMLElement ($ str);

Nu hebben we in een variabele $ xml een object met geparseerde XML wordt opgeslagen. Door toegang te krijgen tot de eigenschappen van dit object, krijgt u toegang tot de inhoud van de XML-tags. Hoe precies - we zullen hieronder een beetje analyseren.

Als XML wordt opgeslagen in een bestand of wordt geretourneerd door een URL te openen (wat meestal het geval is), moet u de functie gebruiken simplexml_load_file wat hetzelfde object maakt $ xml:

Kolya 25 1000

$ xml = simplexml_load_file (pad naar bestand of url);

Hoe te werken

In de onderstaande voorbeelden is onze XML opgeslagen in een bestand of URL.

Laat de volgende XML gegeven worden:

Kolya 25 1000

Laten we de naam, leeftijd en salaris van de werknemer krijgen:

$ xml = simplexml_load_file (pad naar bestand of url); echo $ xml-> naam; // drukt "Kolya" af echo $ xml-> leeftijd; // drukt 25 echo $ xml-> salaris af; // zal 1000 . afdrukken

Zoals u kunt zien, heeft het $ xml-object eigenschappen die overeenkomen met de tags.

Je hebt misschien gemerkt dat de tag komt nergens in het adres voor. Dit komt omdat het de root-tag is. U kunt het hernoemen, bijvoorbeeld naar - en er verandert niets:

Kolya 25 1000

$ xml = simplexml_load_file (pad naar bestand of url); echo $ xml-> naam; // drukt "Kolya" af echo $ xml-> leeftijd; // drukt 25 echo $ xml-> salaris af; // zal 1000 . afdrukken

Er kan slechts één hoofdtag in XML zijn, net als een tag in normale HTML.

Laten we onze XML een beetje aanpassen:

Kolya 25 1000

In dit geval krijgen we een reeks oproepen:

$ xml = simplexml_load_file (pad naar bestand of url); echo $ xml-> werknemer-> naam; // drukt "Kolya" af echo $ xml-> werknemer-> leeftijd; // drukt 25 echo $ xml-> werknemer-> salaris af; // zal 1000 . afdrukken

Werken met attributen

Laat sommige gegevens worden opgeslagen in attributen:

Nummer 1

$ xml = simplexml_load_file (pad naar bestand of url); echo $ xml-> worker ["naam"]; // geeft "Kolya" echo $ xml-> worker ["leeftijd"] weer; // prints 25 echo $ xml-> werknemer ["salaris"]; // drukt 1000 echo $ xml-> worker af; // geeft "Nummer 1" weer

Afgebroken tags

Tags (en attributen) met een koppelteken zijn toegestaan ​​in XML. In dit geval worden dergelijke tags als volgt benaderd:

Kolya Ivanov

$ xml = simplexml_load_file (pad naar bestand of url); echo $ xml-> worker -> (voornaam); // drukt "Kolya" af echo $ xml-> worker -> (achternaam); // geeft "Ivanov" weer

Iteratie over een lus

Laten we nu niet één werknemer hebben, maar meerdere. In dit geval kunnen we ons object herhalen met behulp van een foreach-lus:

Kolya 25 1000 Vasya 26 2000 Peter 27 3000

$ xml = simplexml_load_file (pad naar bestand of url); foreach ($ xml als $ worker) (echo $ worker-> naam; // prints "Kolya", "Vasya", "Petya")

Van object naar normale array

Als u niet vertrouwd bent met het werken met een object, kunt u het met de volgende slimme truc converteren naar een normale PHP-array:

$ xml = simplexml_load_file (pad naar bestand of url); var_dump (json_decode (json_encode ($ xml), waar));

Meer informatie

Parseren op basis van sitemap.xml

Vaak heeft de site een sitemap.xml-bestand. Dit bestand slaat links naar alle pagina's van de site op om ze gemakkelijk te kunnen indexeren door zoekmachines (indexeren is in feite het ontleden van de site door Yandex en Google).

Over het algemeen moeten we er niet veel om geven waarom dit bestand nodig is, het belangrijkste is dat als het bestaat, je de pagina's van de site niet kunt beklimmen met behulp van sluwe methoden, maar gewoon dit bestand kunt gebruiken.

Hoe de aanwezigheid van dit bestand te controleren: laat ons de site.ru-site ontleden, ga dan naar site.ru/sitemap.xml in de browser - als je iets ziet, dan is het daar, en als je het niet ziet , dan helaas.

Als er een sitemap is, dan bevat deze links naar alle pagina's van de site in XML-formaat. Neem rustig deze XML, parseer het, scheid links naar de pagina's die u nodig hebt op een voor u geschikte manier (bijvoorbeeld door de URL te ontleden, die werd beschreven in de spider-methode).

Als gevolg hiervan krijg je een lijst met links voor het parseren, je hoeft er alleen maar naar toe te gaan en de inhoud te ontleden die je nodig hebt.

Lees meer over het sitemap.xml-apparaat in Wikipedia.

Wat nu te doen:

Begin met het oplossen van problemen via de volgende link: taken voor de les.

Als je alles hebt besloten, ga dan verder met het bestuderen van een nieuw onderwerp.


de publicatie van dit artikel is alleen toegestaan ​​met een link naar de website van de auteur van het artikel

In dit artikel laat ik u een voorbeeld zien van hoe u een groot XML-bestand kunt ontleden. Als uw server (hosting) een verhoging van de looptijd van het script niet verbiedt, dan kunt u een XML-bestand met een gewicht van minstens gigabyte ontleden, hij heeft persoonlijk alleen bestanden uit ozon geparseerd met een gewicht van 450 megabyte.

Er zijn twee problemen bij het ontleden van grote XML-bestanden:
1. Niet genoeg geheugen.
2. Er is niet genoeg tijd om het script te laten werken.

Het tweede probleem met tijd kan worden opgelost als de server het niet verbiedt.
Maar het probleem met geheugen is moeilijk op te lossen, zelfs als we het hebben over je eigen server, dan is het niet zo eenvoudig om bestanden van 500 megabyte te verplaatsen, en is het simpelweg niet mogelijk om het geheugen op hosting en op VDS te vergroten.

PHP heeft verschillende ingebouwde XML-verwerkingsopties - SimpleXML, DOM, SAX.
Al deze opties worden gedetailleerd beschreven in veel voorbeeldartikelen, maar alle voorbeelden demonstreren het werken met een volledig XML-document.

Hier is een voorbeeld, een object ophalen uit een XML-bestand

Nu kunt u dit object verwerken, MAAR ...
Zoals u kunt zien, wordt het volledige XML-bestand in het geheugen ingelezen en vervolgens wordt alles geparseerd tot een object.
Dat wil zeggen, alle gegevens gaan naar het geheugen en als het toegewezen geheugen klein is, stopt het script.

Deze optie is niet geschikt voor het verwerken van grote bestanden, u moet het bestand regel voor regel lezen en deze gegevens achtereenvolgens verwerken.
In dit geval wordt de geldigheidscontrole op dezelfde manier uitgevoerd als de gegevensverwerking, dus u moet in staat zijn om terug te draaien, bijvoorbeeld alle gegevens die in de database zijn ingevoerd in het geval van een ongeldig XML-bestand, of maak twee passages door het bestand, lees eerst voor geldigheid, lees dan voor het verwerken van gegevens.

Hier is een theoretisch voorbeeld van het ontleden van een groot XML-bestand.
Dit script leest één teken tegelijk uit het bestand, assembleert die gegevens in blokken en stuurt deze naar de XML-parser.
Deze aanpak lost het geheugenprobleem volledig op en veroorzaakt geen stress, maar verergert het probleem na verloop van tijd. Lees hieronder hoe u het probleem in de loop van de tijd kunt oplossen.

Functie webi_xml ($ bestand)
{

########
### functie voor het werken met data

{
$ gegevens afdrukken;
}
############################################



{
druk $ naam af;
print_r ($ attrs);
}


## eindtag-functie
functie endElement ($ parser, $ naam)
{
druk $ naam af;
}
############################################

($ xml_parser, "gegevens");

// open het bestand
$ fp = fopen ($ bestand, "r");

$ perviy_vxod = 1; $ gegevens = "";



{

$ simvol = fgetc ($ fp); $ gegevens = $ simvol;


if ($ simvol! = ">") (vervolg;)


echo "

pauze;
}

$ gegevens = "";
}
fclose ($fp);

Webi_xml ("1.xml");

?>

In dit voorbeeld plaats ik alles in één functie webi_xml () en helemaal onderaan zie je de aanroep ervan.
Het script zelf bestaat uit drie hoofdfuncties:
1. De functie die de opening van de tag startElement () opvangt
2. Een functie die het sluiten van de tag endElement () opvangt
3. En de functie van het ontvangen van gegevensgegevens ().

Stel dat de inhoud van het bestand 1.xml een recept is



< title >Eenvoudig brood
< ingredient amount = "3" unit = "стакан" >Meel
< ingredient amount = "0.25" unit = "грамм" >Gist
< ingredient amount = "1.5" unit = "стакан" >Warm water
< ingredient amount = "1" unit = "чайная ложка" >Zout
< instructions >
< step > Meng alle ingrediënten en kneed grondig.
< step > Dek af met een doek en laat een uur in een warme kamer staan..
< step > Kneed nog een keer, leg op een bakplaat en zet in de oven.
< step > Bezoek site site


We beginnen allemaal met het aanroepen van de algemene functie webi_xml ("1.xml");
Verder in deze functie start de parser en worden alle tagnamen geconverteerd naar hoofdletters, zodat alle tags hetzelfde hoofdlettergebruik hebben.

$ xml_parser = xml_parser_create ();
xml_parser_set_option ($ xml_parser, XML_OPTION_CASE_FOLDING, waar);

Nu geven we aan welke functies werken om het openen van de tag te vangen, te sluiten en de gegevens te verwerken

xml_set_element_handler ($ xml_parser, "startElement", "endElement");
xml_set_character_data_handler($ xml_parser, "gegevens");

Vervolgens komt het openen van het opgegeven bestand, waarbij het bestand één teken per keer wordt herhaald, en elk teken wordt toegevoegd aan de tekenreeksvariabele totdat het teken is gevonden > .
Als dit de allereerste toegang tot het bestand is, wordt onderweg alles verwijderd dat aan het begin van het bestand overbodig is, alles wat ervoor is , dit is de tag waarmee XML moet beginnen.
Voor de eerste keer zal de stringvariabele de string verzamelen

En stuur haar naar de parser
xml_parse ($ xml_parser, $ data, feof ($ fp));
Na het verwerken van de gegevens wordt de stringvariabele weggegooid en begint de gegevensverzameling in de string opnieuw en wordt de string een tweede keer gevormd

in de derde
</b><br>op de vierde <br><b>Eenvoudig brood

Houd er rekening mee dat de tekenreeksvariabele altijd wordt gevormd door de voltooide tag > en het is niet nodig om bijvoorbeeld een open en gesloten tag met gegevens naar de spider te sturen
Eenvoudig brood
Het is belangrijk dat deze handler een hele niet-gebroken tag krijgt, ten minste één open tag, maar in de volgende stap een gesloten tag, of onmiddellijk 1000 regels van het bestand krijgt, het maakt niet uit, het belangrijkste is dat de tag breekt bijvoorbeeld niet

le> Eenvoudig brood
U kunt op deze manier geen gegevens naar de handler sturen, omdat de tag kapot is.
U kunt uw eigen methode bedenken om gegevens naar de handler te verzenden, bijvoorbeeld elk 1 megabyte aan gegevens verzamelen en naar de handler verzenden om de snelheid te verhogen, zorg er gewoon voor dat de tags altijd zijn voltooid en dat de gegevens kunnen worden verbroken
Gemakkelijk</b><br><b>brood

Zo kun je, in delen zoals je wilt, een groot bestand naar de handler sturen.

Laten we nu eens kijken hoe deze gegevens worden verwerkt en hoe u deze kunt verkrijgen.

Laten we beginnen met de functie voor het openen van tags startElement ($ parser, $ naam, $ attrs)
Stel dat de verwerking de lijn heeft bereikt
< ingredient amount = "3" unit = "стакан" >Meel
Dan is binnen de functie de variabele $ naam gelijk aan ingrediënt dat wil zeggen, de naam van de open tag (het is nog niet zover dat de tag wordt gesloten).
In dit geval is er ook een reeks attributen van deze $ attrs-tag beschikbaar, waarin gegevens hoeveelheid = "3" en eenheid = "glas".

Daarna de verwerking van de gegevens van de open tag met de functie gegevens ($ parser, $ gegevens)
De $ datavariabele bevat alles tussen de openings- en sluitingstags, in ons geval is dit de tekst Meel

En de verwerking van onze string wordt voltooid door de functie endElement ($ parser, $ naam)
Dit is de naam van de gesloten tag, in ons geval is $ name gelijk aan ingrediënt

En daarna ging alles weer in een cirkel.

Het bovenstaande voorbeeld demonstreert alleen het principe van XML-verwerking, maar voor echt gebruik moet het worden verbeterd.
Meestal moet u grote XML ontleden om gegevens in de database in te voeren, en voor een correcte gegevensverwerking moet u weten tot welke open tag de gegevens behoren, tot welk tag-nestingsniveau en welke tags in de hogere hiërarchie open staan. Met deze informatie kunt u het bestand probleemloos verwerken.
Om dit te doen, moet u verschillende globale variabelen invoeren die informatie verzamelen over open tags, nesten en gegevens.
Hier is een voorbeeld dat u kunt gebruiken

Functie webi_xml ($ bestand)
{
globaal $ web_depth; // teller om de nestdiepte bij te houden
$ webi_depth = 0;
globaal $ webi_tag_open; // bevat een array van momenteel geopende tags
$ webi_tag_open = array ();
globaal $ webi_data_temp; // deze array zal de gegevens van één tag bevatten

####################################################
### functie voor het werken met data
functiegegevens ($ parser, $ gegevens)
{
globaal $ web_depth;
globaal $ webi_tag_open;
globaal $ webi_data_temp;
// voeg gegevens toe aan de array die de geneste en momenteel geopende tag aangeeft
$ webi_data_temp [$ webi_depth] [$ webi_tag_open [$ webi_depth]] ["data"]. = $ data;
}
############################################

####################################################
### functie voor het openen van tags
functie startElement ($ parser, $ naam, $ attrs)
{
globaal $ web_depth;
globaal $ webi_tag_open;
globaal $ webi_data_temp;

// als het nestingniveau niet langer nul is, is er al één tag open
// en de gegevens ervan staan ​​al in de array, je kunt het verwerken
als ($ webi_depth)
{




" ;

afdrukken "
" ;
print_r ($ webi_tag_open); // reeks open tags
afdrukken "


" ;

// verwijder na het verwerken van de gegevens om geheugen vrij te maken
uitgeschakeld ($ GLOBALS ["webi_data_temp"] [$ webi_depth]);
}

// nu is het openen van de volgende tag begonnen en vindt verdere verwerking plaats bij de volgende stap
$ webi_depth ++; // nesting vergroten

$ webi_tag_open [$ webi_depth] = $ naam; // voeg de open tag toe aan de informatie-array
$ webi_data_temp [$ webi_depth] [$ naam] ["attrs"] = $ attrs; // voeg nu de tag-attributen toe

}
###############################################

#################################################
## eindtag-functie
functie endElement ($ parser, $ naam) (
globaal $ web_depth;
globaal $ webi_tag_open;
globaal $ webi_data_temp;

// dit is waar de gegevensverwerking begint, bijvoorbeeld toevoegen aan de database, opslaan in een bestand, enz.
// $ webi_tag_open bevat een reeks open tags op nestniveau
// bijvoorbeeld $ webi_tag_open [$ webi_depth] bevat de naam van de open tag waarvan de informatie momenteel wordt verwerkt
// $ webi_depth tag nesting niveau
// $ webi_data_temp [$ webi_depth] [$ webi_tag_open [$ webi_depth]] ["attrs"] reeks tagkenmerken
// $ webi_data_temp [$ webi_depth] [$ webi_tag_open [$ webi_depth]] ["data"] taggegevens

Druk "gegevens" af. $ webi_tag_open [$ webi_depth]. "-". ($ webi_data_temp [$ webi_depth] [$ webi_tag_open [$ webi_depth]] ["data"]). "
" ;
print_r ($ webi_data_temp [$ webi_depth] [$ webi_tag_open [$ webi_depth]] ["attrs"]);
afdrukken "
" ;
print_r ($ webi_tag_open);
afdrukken "


" ;

Uitgeschakeld ($ GLOBALS ["webi_data_temp"]); // verwijder na het verwerken van de gegevens de hele array met gegevens, aangezien de tag was gesloten
uitgeschakeld ($ GLOBALS ["webi_tag_open"] [$ webi_depth]); // verwijder informatie over deze open tag ... aangezien deze is gesloten

$ webi_diepte -; // verminder nesten
}
############################################

$ xml_parser = xml_parser_create ();
xml_parser_set_option ($ xml_parser, XML_OPTION_CASE_FOLDING, waar);

// specificeer welke functies werken bij het openen en sluiten van tags
xml_set_element_handler ($ xml_parser, "startElement", "endElement");

// specificeer een functie voor het werken met data
xml_set_character_data_handler($ xml_parser, "gegevens");

// open het bestand
$ fp = fopen ($ bestand, "r");

$ perviy_vxod = 1; // vlag om de eerste bestandsinvoer te controleren
$ gegevens = ""; // hier verzamelen we gegevens uit het bestand in delen en sturen het naar de xml-parser

// loop totdat het einde van het bestand is gevonden
terwijl (! feof ($ fp) en $ fp)
{
$ simvol = fgetc ($ fp); // lees één teken uit bestand
$ gegevens = $ simvol; // voeg dit symbool toe aan de te verzenden gegevens

// als het teken geen eindtag is, gaan we terug naar het begin van de lus en voegen we een ander teken toe aan de gegevens, enzovoort totdat de eindtag is gevonden
if ($ simvol! = ">") (vervolg;)
// als er een afsluitende tag is gevonden, stuur deze verzamelde gegevens nu voor verwerking

// controleer of dit het eerste item in het bestand is, verwijder dan alles wat voor de tag staat// aangezien soms rommel kan worden gevonden voor het begin van XML (onhandige editors, of het bestand wordt ontvangen door een script van een andere server)
if ($ perviy_vxod) ($ data = strstr ($ data, "

// nu gooien we de gegevens in de xml-parser
if (! xml_parse ($ xml_parser, $ data, feof ($ fp))) (

// hier kunt u fouten voor geldigheid verwerken en krijgen ...
// zodra er een fout wordt aangetroffen, stopt het parseren
echo "
XML-fout: ". Xml_error_string (xml_get_error_code ($ xml_parser));
echo "op lijn". xml_get_current_line_number ($ xml_parser);
pauze;
}

// gooi na het ontleden de verzamelde gegevens weg voor de volgende stap van de cyclus.
$ gegevens = "";
}
fclose ($fp);
xml_parser_free ($ xml_parser);
// verwijder globale variabelen
uitgeschakeld ($ GLOBALS ["webi_depth"]);
uitgeschakeld ($ GLOBALS ["webi_tag_open"]);
uitgeschakeld ($ GLOBALS ["webi_data_temp"]);

Webi_xml ("1.xml");

?>

Het hele voorbeeld ging vergezeld van opmerkingen, nu testen en experimenteren.
Houd er rekening mee dat in de functie van werken met gegevens, gegevens niet eenvoudig in een array worden ingevoegd, maar worden toegevoegd met " .=" aangezien de gegevens mogelijk niet in hun geheel komen en als u een eenvoudige opdracht maakt, ontvangt u van tijd tot tijd gegevens in brokken.

Dat is alles, nu is er genoeg geheugen bij het verwerken van een bestand van elke grootte, maar de looptijd van het script kan op verschillende manieren worden verhoogd.
Voeg aan het begin van het script de functie in
set_time_limit (6000);
of
ini_set ("max_execution_time", "6000");

Of voeg de tekst toe aan uw .htaccess-bestand
php_value max_execution_time 6000

Deze voorbeelden verhogen de looptijd van het script tot 6000 seconden.
U kunt de tijd op deze manier alleen in de uitgeschakelde modus verlengen.

Als je toegang hebt om php.ini te bewerken, kun je de tijd verlengen met
max_execution_time = 6000

Op de hosting masterhost is het op het moment van schrijven bijvoorbeeld verboden om de scripttijd te verlengen, ondanks de uitgeschakelde veilige modus, maar als je een professional bent, kun je je eigen php-assemblage maken op de masterhost, maar dit is niet daarover in dit artikel.

Sommige van de voorbeelden in deze zelfstudie bevatten een XML-tekenreeks. In plaats van het in elk voorbeeld te herhalen, plaatst u die regel in een bestand, dat u in elk voorbeeld opneemt. Deze lijn wordt getoond in het volgende voorbeeld. Bovendien kunt u een XML-document maken en lezen met de functie simplexml_load_file ().

Voorbeeld # 1 Voorbeeld.php-bestand met XML-tekenreeks

$ xmlstr =<<


PHP: Introductie van de Parser


Mevr. Codeur
Onlivia Actora


Dhr. Codeur
El ActÓr


Het is dus een taal. Het is en blijft een programmeertaal. Of
is het een scripttaal? Alles wordt onthuld in deze documentaire
als een horrorfilm.




7
5


xml;
?>

SimpleXML is gemakkelijk te gebruiken! Probeer een string of nummer uit het onderliggende XML-document te halen.

Voorbeeld #2 Ophalen van een deel van een document

omvatten "voorbeeld.php";

echo $ films -> film [0] -> plot;
?>

Het is dus een taal. Het is en blijft een programmeertaal. Of is het een scripttaal? Alles komt aan het licht in deze horrorachtige documentaire.

In PHP kunt u toegang krijgen tot een element in een XML-document dat ongeldige tekens (zoals een koppelteken) in de naam bevat door de gegeven elementnaam tussen accolades en apostrofs te plaatsen.

Voorbeeld # 3 Een string ophalen

omvatten "voorbeeld.php";

echo $ movies -> movie -> ("grote lijnen") -> lijn;
?>

Het resultaat van dit voorbeeld:

PHP lost al mijn webproblemen op

Voorbeeld #4 Toegang tot niet-unieke elementen in SimpleXML

In het geval dat er meerdere instanties van onderliggende elementen in één bovenliggend element zijn, moet u de standaard iteratiemethoden gebruiken.

omvatten "voorbeeld.php";

$ films = nieuw SimpleXMLElement ($ xmlstr);

/ * Voor elk knooppunt , we zullen de naam apart weergeven . */
foreach ($ films -> film -> tekens -> teken als $ teken) (
echo $ karakter -> naam, "spelend", $ karakter -> acteur, PHP_EOL;
}

?>

Het resultaat van dit voorbeeld:

Mevr. Coder gespeeld door Onlivia Actora Mr. Coder gespeeld door El ActÓr

Commentaar:

Eigenschappen ( $ films-> film in het vorige voorbeeld) zijn geen arrays. Het is een itereerbaar als een array.

Voorbeeld # 5 Kenmerken gebruiken

Tot nu toe kregen we alleen de namen en waarden van de elementen. SimpleXML heeft ook toegang tot de attributen van een element. Een elementattribuut kan op dezelfde manier worden benaderd als arrayelementen ( reeks).

omvatten "voorbeeld.php";

$ films = nieuw SimpleXMLElement ($ xmlstr);

/ * Toegang tot het knooppunt het eerste filmpje.
* We zullen ook de beoordelingsschaal weergeven. * /
foreach ($ films -> film [0] -> waardering als $ waardering) (
switch ((string) $ rating ["type"]) ( // Haal de attributen van het element op per index
geval "duimen":
echo $ waardering, "duim omhoog";
pauze;
geval "sterren":
echo $ waardering, "sterren";
pauze;
}
}
?>

Het resultaat van dit voorbeeld:

7 duimen omhoog5 sterren

Voorbeeld # 6 Elementen en attributen vergelijken met tekst

Om een ​​element of attribuut met een tekenreeks te vergelijken, of om het als tekst aan een functie door te geven, moet u het naar een tekenreeks casten met (snaar)... Anders behandelt PHP het element als een object.

omvatten "voorbeeld.php";

$ films = nieuw SimpleXMLElement ($ xmlstr);

if ((string) $ movies -> movie -> title == "PHP: De opkomst van de parser") {
afdrukken "Mijn favoriete film.";
}

echo htmlentities ((string) $ movies -> movie -> titel);
?>

Het resultaat van dit voorbeeld:

Mijn favoriete film Php: The Emergence of the Parser

Voorbeeld # 7 Twee items vergelijken

Twee SimpleXMLElements worden als verschillend beschouwd, zelfs als ze naar hetzelfde object verwijzen sinds PHP 5.2.0.

omvatten "voorbeeld.php";

$ movies1 = nieuw SimpleXMLElement ($ xmlstr);
$ movies2 = nieuw SimpleXMLElement ($ xmlstr);
var_dump ($ films1 == $ films2); // false sinds PHP 5.2.0
?>

Het resultaat van dit voorbeeld:

Voorbeeld # 8 XPath gebruiken

SimpleXML bevat ingebouwde XPath-ondersteuning. Vind alle items :

omvatten "voorbeeld.php";

$ films = nieuw SimpleXMLElement ($ xmlstr);

foreach ($ movies -> xpath ("// character") als $ character) (
echo $ karakter -> naam, "spelend", $ karakter -> acteur, PHP_EOL;
}
?>

"// "dient als een sjabloon. Om een ​​absoluut pad op te geven, laat u een van de schuine strepen naar voren weg.

Het resultaat van dit voorbeeld:

Mevr. Coder gespeeld door Onlivia Actora Mr. Coder gespeeld door El ActÓr

Voorbeeld # 9 Waarden instellen

Gegevens in SimpleXML hoeven niet onveranderlijk te zijn. Met het object kunt u alle elementen manipuleren.

omvatten "voorbeeld.php";
$ films = nieuw SimpleXMLElement ($ xmlstr);

$ movies -> movie [0] -> karakters -> karakter [0] -> naam = "Miss Coder";

echo $ films -> asXML ();
?>

Het resultaat van dit voorbeeld:

PHP: Introductie van de Parser Miss codeur Onlivia Actora Dhr. Codeur El ActÓr 7 5

Voorbeeld #10 Elementen en attributen toevoegen

Sinds PHP 5.1.3 heeft SimpleXML de mogelijkheid om eenvoudig onderliggende elementen en attributen toe te voegen.

omvatten "voorbeeld.php";
$ films = nieuw SimpleXMLElement ($ xmlstr);

$ karakter = $ films -> film [0] -> tekens -> addChild ("karakter");
$ karakter -> addChild ("naam", "Mr. Parser");
$ karakter -> addChild ("acteur", "John Doe");

$ rating = $ films -> film [0] -> addChild ("beoordeling", "PG");
$ rating -> addAttribute ("type", "mpaa");

echo $ films -> asXML ();
?>

Het resultaat van dit voorbeeld:

PHP: Introductie van de Parser Mevr. Codeur Onlivia Actora Dhr. Codeur El ActÓr Dhr. ParserJohn Doe Het is dus een taal. Het is en blijft een programmeertaal. Of is het een scripttaal? Alles komt aan het licht in deze horrorachtige documentaire. PHP lost al mijn webtaken op 7 5 PG

Voorbeeld # 11 Interactie met de DOM

PHP kan XML-knooppunten converteren van SimpleXML naar DOM-formaat en vice versa. Dit voorbeeld laat zien hoe u een DOM-element in SimpleXML kunt wijzigen.

$ dom = nieuw DOMDocument;
$ dom -> loadXML ( "onzin" );
als (! $ dom) (
echo "Er is een fout opgetreden tijdens het ontleden van het document";
Uitgang;
}

$ boeken = simplexml_import_dom ($ dom);

echo $ boeken -> boek [0] -> titel;
?>

Het resultaat van dit voorbeeld:

4 jaar geleden

Er is een algemene "truc" die vaak wordt voorgesteld om een ​​SimpleXML-object naar een array te converteren, door het eerst door json_encode () en vervolgens door json_decode () te laten lopen. Ik wil graag uitleggen waarom dit een slecht idee is.

Heel eenvoudig, omdat het hele doel van SimpleXML is om gemakkelijker te gebruiken en krachtiger te zijn dan een gewone array. U kunt bijvoorbeeld schrijven:bar -> baz ["bing"]?> en het betekent hetzelfde alsbar [0] -> baz [0] ["bing"]?>, ongeacht het aantal bar- of baz-elementen in de XML; en als je schrijftbar [0] -> baz [0]?> je krijgt alle stringinhoud van dat knooppunt - inclusief CDATA-secties - ongeacht of het ook onderliggende elementen of attributen heeft. U hebt ook toegang tot naamruimte-informatie, de mogelijkheid om eenvoudige wijzigingen aan de XML aan te brengen en zelfs de mogelijkheid om te "importeren" in een DOM-object, voor veel krachtigere manipulatie. Dit gaat allemaal verloren door het object in een array te veranderen in plaats van de voorbeelden op deze pagina te lezen.

Bovendien, omdat het niet voor dit doel is ontworpen, zal de conversie naar JSON en terug in sommige situaties zelfs informatie verliezen. Alle elementen of attributen in een naamruimte worden bijvoorbeeld gewoon weggegooid en alle tekstinhoud wordt weggegooid als een element ook kinderen of attributen heeft. Soms maakt dit "niet uit, maar als je de gewoonte krijgt om alles naar arrays te converteren, zal het je uiteindelijk steken.

Natuurlijk zou je een slimmere conversie kunnen schrijven, die deze beperkingen niet had, maar op dat moment haal je helemaal geen waarde uit SimpleXML, en zou je gewoon de lagere XML Parser-functies of de XMLReader-klasse moeten gebruiken, om uw structuur te creëren. U heeft nog steeds "niet de extra gemaksfunctionaliteit van SimpleXML, maar dat" is uw verlies.

2 jaar geleden

Als uw xml-tekenreeks booleans bevat die zijn gecodeerd met "0" en "1", zult u problemen tegenkomen wanneer u het element rechtstreeks naar bool cast:

$ xmlstr =<<

1
0

xml;
$ waarden = nieuw SimpleXMLElement ($ xmlstr);
$ truevalue = (bool) $ values-> truevalue; // waar
$ valse waarde = (bool) $ waarden-> valse waarde; // ook waar!!!

In plaats daarvan moet je eerst naar string of int casten:

$ truevalue = (bool) (int) $ values-> truevalue; // waar
$ valse waarde = (bool) (int) $ waarden-> valse waarde; // false

9 jaar geleden

Als u geldige xml in uw antwoord moet uitvoeren, vergeet dan niet om uw header-inhoudstype in te stellen op xml, naast het weergeven van het resultaat van asXML ():

$ xml = simplexml_load_file ("...");
...
... xml-dingen
...

// voer xml uit in je reactie:
header ("Inhoudstype: tekst / xml");
echo $ xml -> asXML ();
?>

9 jaar geleden

Uit het README-bestand:

SimpleXML is bedoeld als een gemakkelijke manier om toegang te krijgen tot XML-gegevens.

SimpleXML-objecten volgen vier basisregels:

1) eigenschappen duiden element-iterators aan
2) numerieke indexen geven elementen aan
3) niet-numerieke indices duiden attributen aan
4) stringconversie geeft toegang tot TEKST-gegevens

Bij het itereren van eigenschappen itereert de extensie altijd over
alle knooppunten met die elementnaam. Dus methode kinderen () moeten zijn
opgeroepen om over subnodes te itereren. Maar doe ook het volgende:
foreach ($ obj-> node_name als $ elem) (
// doe iets met $ elem
}
resulteert altijd in herhaling van "node_name" -elementen. Dus niet verder
controle is nodig om het aantal knooppunten van dat type te onderscheiden.

Wanneer een element TEXT data wordt benaderd via een eigenschap
dan bevat het resultaat niet de TEKST-gegevens van subelementen.

Bekende problemen
============

Vanwege motorproblemen is het momenteel niet mogelijk om toegang te krijgen
een subelement door index 0: $ object-> eigenschap.

8 jaar geleden

Het gebruik van dingen als: is_object ($ xml-> module-> admin) om te controleren of er daadwerkelijk een knooppunt met de naam "admin" is, lijkt niet te werken zoals verwacht, aangezien simplexml altijd een object retourneert - in dat geval een lege - zelfs als een bepaald knooppunt niet bestaat.
Voor mij lijkt de goede oude lege () functie in dergelijke gevallen prima te werken.

8 jaar geleden

Een snelle tip over xpath-query's en standaardnaamruimten. Het lijkt erop dat het XML-systeem achter SimpleXML dezelfde werking heeft als ik denk dat het XML-systeem .NET gebruikt: wanneer men iets in de standaardnaamruimte moet adresseren, moet men de naamruimte declareren met registerXPathNamespace en vervolgens het voorvoegsel gebruiken om adresseer het anders in het standaard levende element van de naamruimte.

$ tekenreeks =<<

Veertig Wat?
Joe
Jane

Ik weet dat dat het antwoord is, maar wat is de vraag?




xml;

$ xml = simplexml_load_string ($ string);
$ xml -> registerXPathNamespace ("def", "http://www.w3.org/2005/Atom");

$ nodes = $ xml -> xpath ("// def: document / def: titel");

?>

9 jaar geleden

Hoewel SimpleXMLElement beweert itereerbaar te zijn, lijkt het de standaard Iterator-interfacefuncties zoals :: next en :: reset niet correct te implementeren. Daarom, terwijl foreach () werkt, lijken functies zoals next (), current (), of each () niet te werken zoals je zou verwachten - de aanwijzer lijkt nooit te bewegen of wordt steeds opnieuw ingesteld.

6 jaar geleden

Als de codering van het XML-document afwijkt van UTF-8, moet de coderingsdeclaratie onmiddellijk volgen na versie = "..." en vóór standalone = "...". Dit is een vereiste van de XML-standaard.

Als codering XML-document verschilt van UTF-8. Coderingsdeclaratie moet onmiddellijk volgen na de versie = "..." en vóór standalone = "...". Deze vereiste is standaard XML.


OK

Russische taal. Russische taal


Fatale fout: niet-gevangen uitzondering "Uitzondering" met bericht "String kan niet worden geparseerd als XML" in ...

Extensible Markup Language XML is een set regels voor het coderen van documenten in machineleesbare vorm. XML is een populair formaat voor het uitwisselen van gegevens op internet. Sites die hun inhoud regelmatig bijwerken, zoals nieuwssites of blogs, bieden vaak een XML-feed om externe programma's op de hoogte te houden van wijzigingen in de inhoud. Het verzenden en parseren van XML-gegevens is een veelvoorkomende taak voor netwerktoepassingen. In deze les wordt uitgelegd hoe u XML-documenten kunt ontleden en hun gegevens kunt gebruiken.

Een parser kiezen

Kanaalanalyse

De eerste stap bij het ontleden van een feed is beslissen in welke gegevensvelden u geïnteresseerd bent. De parser extraheert de opgegeven velden en negeert al het andere.

Hier is een feedfragment dat in de voorbeeldtoepassing wordt onderzocht. Elk bericht op StackOverflow.com verschijnt in de feed als een entry-tag die verschillende geneste tags bevat:

nieuwste vragen getagd android a-shops-ranking.com ... ... http://stackoverflow.com/q/9439999 0 Waar is mijn gegevensbestand? klif2310 http://stackoverflow.com/users/1128925 2012-02-25T00: 30: 54Z 2012-02-25T00: 30: 54Z

Ik heb een applicatie waarvoor een gegevensbestand nodig is ...

... ...

De voorbeeld-app haalt gegevens uit de invoertag en de titel, link en samenvatting van de subtags.

De parser instantiëren

De volgende stap is om de parser te instantiëren en het parseerproces te starten. Dit fragment initialiseert de parser om naamruimten niet te verwerken en gebruikt de opgegeven InputStream als invoer. Het parseerproces wordt gestart door nextTag () aan te roepen en de methode readFeed () aan te roepen, die de gegevens ophaalt en verwerkt waarin de toepassing is geïnteresseerd:

Openbare klasse StackOverflowXmlParser (// We gebruiken geen namespaces private static final String ns = null; public List parse (InputStream in) gooit XmlPullParserException, IOException (try (XmlPullParser parser = Xml.newPullParser (, false_server.XmlFeature) ); parser.setInput (in, null); parser.nextTag (); return readFeed (parser);) eindelijk (in.close ();)) ...)

kanaal aftrekken

De methode readFeed () doet het eigenlijke werk van het verwerken van de feed. Items die zijn gemarkeerd met de tag "entry" zijn het startpunt voor recursieve kanaalverwerking. Als de volgende tag geen entry-tag is, wordt deze overgeslagen. Nadat de volledige feed recursief is verwerkt, retourneert readFeed () een lijst met de items (inclusief geneste gegevensitems) die uit de feed zijn opgehaald. Deze lijst wordt vervolgens geretourneerd door de parser.

Private List readFeed (XmlPullParser-parser) genereert XmlPullParserException, IOException (List-items = new ArrayList (); parser.require (XmlPullParser.START_TAG, ns, "feed"); terwijl (parser.next ()! = XmlPullParser.END_TAGParser. getEventType ()! = XmlPullParser.START_TAG) (doorgaan;) Stringnaam = parser.getName (); // Begint door te zoeken naar de entry-tag if (name.equals ("entry")) (entries.add ( readEntry (parser ));) else (overslaan (parser);)) retouren invoeren;)

XML parseren

De stappen voor het ontleden van een XML-feed zijn als volgt:

Dit fragment laat zien hoe de parser het item, de titel, de link en de samenvatting ontleedt.

Openbare statische klasse Entry (openbare finale String-titel; openbare finale String-link; openbare finale String-samenvatting; privé-invoer (String-titel, String-samenvatting, String-link) (this.title = title; this.summary = samenvatting; this.link = link ;)) // Parseert de inhoud van een item. Als het een titel, samenvatting of link-tag tegenkomt, geef ze // door aan hun respectievelijke "lees"-methoden voor verwerking. Anders wordt de tag overgeslagen. private Entry readEntry (XmlPullParser-parser) genereert XmlPullParserException, IOException (parser.require (XmlPullParser.START_TAG, ns, "entry"); String titel = null; String samenvatting = null; String link = null; while (parser.next ()! = XmlPullParser.END_TAG) (if (parser.getEventType ()! = XmlPullParser.START_TAG) (doorgaan;) Stringnaam = parser.getName (); if (name.equals ("titel")) (title = readTitle (parser) ;) else if (name.equals ("samenvatting")) (summary = readSummary (parser);) else if (name.equals ("link")) (link = readLink (parser);) else (skip (parser) ;)) retourneer nieuwe invoer (titel, samenvatting, link);) // Verwerkt titeltags in de feed. private String readTitle (XmlPullParser-parser) genereert IOException, XmlPullParserException (parser.require (XmlPullParser.START_TAG, ns, "title"); String title = readText (parser); parser.require (XmlPullParser title.END; "title"); ) // Verwerkt linktags in de feed. private String readLink (XmlPullParser-parser) genereert IOException, XmlPullParserException (String link = ""; parser.require (XmlPullParser.START_TAG, ns, "link"); String tag = parser.getName (); String relType = parser.e , "rel"); if (tag.equals ("link")) (if (relType.equals ("alternate")) (link = parser.getAttributeValue (null, "href"); parser.nextTag ();) ) parser.require (XmlPullParser.END_TAG, ns, "link"); retourlink;) // Verwerkt samenvattingstags in de feed. private String readSummary (XmlPullParser-parser) genereert IOException, XmlPullParserException (parser.require (XmlPullParser.START_TAG, ns, "summary"); String summary = readText (parser); parser.require (XmlPullParser", samenvatting ) // Extraheert voor de titel en samenvatting van de tags hun tekstwaarden. private String readText (XmlPullParser-parser) genereert IOException, XmlPullParserException (String result = ""; if (parser.next () == XmlPullParser.TEXT) (result = parser.getText (); parser.nextTag ();) retourneert resultaat; ) ...)

Items overslaan die je niet nodig hebt

In een van de hierboven beschreven XML-parseerstappen slaat de parser tags over waarin we niet geïnteresseerd zijn. Hieronder staat de code van de skip () methode-parser:

Private void skip (XmlPullParser-parser) genereert XmlPullParserException, IOException (if (parser.getEventType ()! = XmlPullParser.START_TAG) (gooi nieuwe IllegalStateException ();) int depth = 1; while ( depth! = 0) (switch (parser. next ()) (case XmlPullParser.END_TAG: depth--; break; case XmlPullParser.START_TAG: depth ++; break;)))

Dit is hoe het werkt:

  • De methode genereert een uitzondering als de huidige gebeurtenis niet START_TAG is.
  • Het verbruikt START_TAG en alle evenementen tot END_TAG.
  • Om ervoor te zorgen dat het stopt bij de juiste END_TAG en niet bij de eerste ontmoetingstag na de oorspronkelijke START_TAG, houdt het de nestdiepte bij.

Dus als het huidige element geneste elementen heeft, is de dieptewaarde pas 0 als de parser alle gebeurtenissen tussen de oorspronkelijke START_TAG en de bijbehorende END_TAG heeft verwerkt. Overweeg bijvoorbeeld hoe de analysator mist een element dat 2 geneste elementen heeft, en :

  • In de eerste doorgang door de while-lus, de volgende tag die de analysator daarna tegenkomt dit is START_TAG voor
  • In de tweede passage door de while-lus is de volgende tag die de analysator tegenkomt END_TAG
  • In de derde passage door de while-lus is de volgende tag die de analysator tegenkomt START_TAG ... De dieptewaarde wordt verhoogd naar 2.
  • In de vierde passage door de while-lus is de volgende tag die de analysator tegenkomt END_TAG... De dieptewaarde neemt af naar 1.
  • Bij de vijfde en laatste passage door de while-lus is de volgende tag die de analysator tegenkomt END_TAG... Diepte neemt af tot 0, wat aangeeft dat: het item is succesvol overgeslagen.

XML-gegevensverwerking

De voorbeeldtoepassing ontvangt en parseert een XML-feed in een AsyncTask. De verwerking vindt plaats buiten de hoofd-UI-thread. Wanneer de verwerking is voltooid, werkt de toepassing de gebruikersinterface bij in de hoofdactiviteit (Netwerkactiviteit).

In het onderstaande fragment doet de methode loadPage () het volgende:

  • Initialiseert een tekenreeksvariabele met een URL-waarde die verwijst naar een XML-feed.
  • Als gebruikersinstellingen en netwerkconnectiviteit het toelaten, roept nieuwe DownloadXmlTask ​​​​(). Uitvoeren (url). Hiermee wordt een nieuw DownloadXmlTask-object (AsyncTask-subklasse) gemaakt en wordt de methode execute () uitgevoerd, die het kanaal downloadt en parseert en een tekenreeksresultaat retourneert dat in de gebruikersinterface wordt weergegeven.
public class NetworkActivity breidt activiteit uit (public static final String WIFI = "Wi-Fi"; public static final String ANY = "Any"; private static final String URL = "http://stackoverflow.com/feeds/tag?tagnames=android&sort = nieuwste "; // Of er een wifi-verbinding is. private static boolean wifiConnected = false; // Of er een mobiele verbinding is. private static boolean mobileConnected = false; // Of het scherm vernieuwd moet worden. public static boolean refreshDisplay = true; public static String sPref = null; ... // Gebruikt AsyncTask om de XML-feed te downloaden van stackoverflow.com. public void loadPage () (if ((sPref.equals (ANY)) && (wifiConnected || mobileConnected )) (nieuwe DownloadXmlTask ​​​​(). execute (URL);) else if ((sPref.equals (WIFI)) && (wifiConnected)) (nieuwe DownloadXmlTask ​​​​(). execute (URL);) else (// toon fout))
  • doInBackground () voert de methode loadXmlFromNetwork () uit. Het geeft de URL van het kanaal door als parameter. De methode loadXmlFromNetwork () ontvangt en verwerkt het kanaal. Wanneer het klaar is met verwerken, geeft het de resulterende string terug.
  • onPostExecute () neemt de geretourneerde tekenreeks en geeft deze weer in de gebruikersinterface.
// Implementatie van AsyncTask gebruikt om XML-feed te downloaden van stackoverflow.com. privéles DownloadXmlTask ​​​​verlengt AsyncTask (@Override protected String doInBackground (String ... urls) (try (return loadXmlFromNetwork (urls);) catch (IOException e) (return getResources (). GetString (R.string.connection_error);) catch (XmlPullParserException e) ( return getResources (). getString (R.string.xml_error);)) @Override protected void onPostExecute (String resultaat) (setContentView (R.layout.main); // Geeft de HTML-string in de gebruikersinterface weer via een WebView WebView myWebView = (WebView) findViewById (R.id.webview); myWebView.loadData (resultaat, "text / html", null);))

Hieronder vindt u de methode loadXmlFromNetwork () die wordt aangeroepen vanuit DownloadXmlTask. Het doet het volgende:

  1. Maakt een instantie van StackOverflowXmlParser. Het creëert ook variabelen voor List Entry-objecten (items), en titel, url en samenvatting, om de waarden op te slaan die zijn opgehaald uit de XML-feed voor deze velden.
  2. Roept downloadUrl () aan, die het kanaal downloadt en retourneert als een InputStream.
  3. Gebruikt StackOverflowXmlParser om InputStream te ontleden. De StackOverflowXmlParser vult de lijstvermeldingen met gegevens uit de feed.
  4. Verwerkt een invoerlijst en combineert feedgegevens met HTML-opmaak.
  5. Retourneert de HTML-tekenreeks die wordt weergegeven in de gebruikersinterface van de hoofdactiviteit, AsyncTask in de methode onPostExecute ().
// Uploadt XML van stackoverflow.com, analyseert het en combineert het met // HTML-opmaak. Retourneert HTML-tekenreeks. private String loadXmlFromNetwork (String urlString) gooit XmlPullParserException, IOException (InputStream stream = null; // Instantieer de parser StackOverflowXmlParser stackOverflowXmlParser = nieuwe StackOverflowXmlParser (); Lijst invoer = null; Stringtitel = null; String-url = null; Stringsamenvatting = null; Kalender rightNow = Kalender.getInstance (); DateFormat formatter = nieuwe SimpleDateFormat ("MMM dd h: mmaa"); // Controleert of de gebruiker de voorkeur heeft ingesteld om samenvattende tekst op te nemen SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences (this); boolean pref = sharedPrefs.getBoolean ("summaryPref", false); StringBuilder htmlString = nieuwe StringBuilder (); htmlString.append ("

"+ getResources (). getString (R.string.page_title) +"

"); htmlString.append (" "+ getResources (). getString (R.string.updated) +" "+ formatter.format (rightNow.getTime ()) +""); probeer (stream = downloadUrl (urlString); entries = stackOverflowXmlParser.parse (stream); // Zorgt ervoor dat de InputStream wordt gesloten nadat de app // klaar is met het gebruik ervan.) eindelijk (if (stream! = null) (stream.close ();)) // StackOverflowXmlParser retourneert een lijst (genaamd "entry's") van Entry-objecten. // Elk Entry-object vertegenwoordigt een enkele post in de XML-feed. // In deze sectie wordt de lijst met items verwerkt om elk item te combineren item met HTML-opmaak. // Elk item wordt in de gebruikersinterface weergegeven als een link die optioneel // een tekstsamenvatting bevat. voor (itemitem: items) (htmlString.append ("

"+ invoer.titel +"

"); // Als de gebruiker de voorkeur heeft ingesteld om samenvattingstekst op te nemen, // voegt deze toe aan het scherm. If (pref) (htmlString.append (entry.summary);)) return htmlString.toString ();) // Gegeven een tekenreeksrepresentatie van een URL, zet een verbinding op en krijgt // een invoerstroom.private InputStream downloadUrl (String urlString) gooit IOException (URL url = nieuwe URL (urlString); HttpURLConnection conn = (HttpURLConnection) url.openConnection () ; conn.setReadTimeout (10000 / * milliseconden * /); conn.setConnectTimeout (15000 / * milliseconden * /); conn.setRequestMethod ("GET"); conn.setDoInput (true); // Start de query conn.connect ( ); retourneer conn.getInputStream ();)