Finestre.  Virus.  I Quaderni.  Internet.  ufficio.  Utilità.  Autisti

Analizzare XML significa essenzialmente passare attraverso un documento XML e restituire i dati corrispondenti. E sebbene tutto Di più i servizi Web restituiscono i dati in formato JSON, ma la maggior parte utilizza ancora XML, quindi è importante padroneggiarli Analisi XML se desideri utilizzare l'intera gamma di API disponibili.

Utilizzando l'estensione SimpleXML in PHP, che è stato aggiunto in PHP 5.0, lavorare con XML è molto facile e semplice. In questo articolo, ti mostrerò come farlo.

Nozioni di base sull'utilizzo

Iniziamo con il seguente esempio lingue.xml:


>

> 1972>
> Dennis Richie >
>

> 1995>
> Rasmus Lerdorf >
>

> 1995>
> James Gosling >
>
>

Questo documento XML contiene un elenco di linguaggi di programmazione con alcune informazioni su ogni linguaggio: l'anno della sua implementazione e il nome del suo creatore.

Il primo passaggio consiste nel caricare l'XML utilizzando le funzioni simplexml_load_file(), O simplexml_load_string(). Come suggerisce il nome delle funzioni, la prima caricherà XML da un file e la seconda caricherà XML da una stringa.

Entrambe le funzioni leggono l'intero albero DOM in memoria e restituiscono un oggetto SimpleXMLElement. Nell'esempio sopra, l'oggetto è memorizzato nella variabile $languages. Puoi usare le funzioni var_dump() O stampa_r() per ottenere informazioni dettagliate sull'oggetto restituito, se lo desideri.

Oggetto SimpleXMLElement
[lang] => matrice
[ 0 ] => SimpleXMLElementObject
[@attributes] => Array
[nome] => c
[apparso] => 1972
[ creatore] => Dennis Ritchie
[ 1 ] => Oggetto SimpleXMLElement
[@attributes] => Array
[nome] => PHP
[apparso] => 1995
[ creatore] => Rasmus Lerdorf
[ 2 ] => Oggetto SimpleXMLElement
[@attributes] => Array
[nome] => Java
[apparso] => 1995
[ creatore] => James Gosling
)
)

Questo XML contiene l'elemento radice le lingue, che contiene tre elementi lang. Ogni elemento dell'array corrisponde a un elemento lingua in un documento XML.

È possibile accedere alle proprietà di un oggetto utilizzando l'operatore -> . Ad esempio, $languages->lang ti restituirà un oggetto SimpleXMLElement che corrisponde al primo elemento lingua. Questo oggetto contiene due proprietà: apparso e creatore.

$languages ​​​​-> lang [ 0 ] -> apparso ;
$lingue -> lingua [ 0 ] -> creatore ;

Visualizzare un elenco di lingue e visualizzarne le proprietà è molto semplice con un ciclo standard come per ciascuno.

foreach ($lingue -> lang come $lang ) (
stampaf (
"" ,
$lang["nome"] ,
$lang -> apparso,
$lang -> creatore
) ;
}

Si noti come ho effettuato l'accesso al nome dell'attributo dell'elemento lang per ottenere il nome della lingua. In questo modo è possibile accedere a qualsiasi attributo di un elemento rappresentato come oggetto SimpleXMLElement.

Lavorare con i namespace

Mentre lavori con l'XML di vari servizi Web, incontrerai spesso spazi dei nomi degli elementi. Cambiamo il nostro lingue.xml per mostrare un esempio di utilizzo di uno spazio dei nomi:



xmlns:dc =>

> 1972>
> Dennis Richie >
>

> 1995>
> Rasmus Lerdorf >
>

> 1995>
> James Gosling >
>
>

Ora elemento Creatore collocato nello spazio dei nomi dc, che rimanda a http://purl.org/dc/elements/1.1/. Se provi a stampare i creatori di lingua utilizzando il nostro codice precedente, non funzionerà. Per leggere gli spazi dei nomi degli elementi è necessario utilizzare uno dei seguenti approcci.

Il primo approccio consiste nell'utilizzare i nomi URI direttamente nel codice quando si fa riferimento allo spazio dei nomi dell'elemento. L'esempio seguente mostra come questo è fatto:

$dc = $lingue -> lingua [ 1 ] -> bambini( "http://purl.org/dc/elements/1.1/") ;
echo $dc -> creatore ;

Metodo bambini() accetta uno spazio dei nomi e restituisce elementi figlio che iniziano con un prefisso. Richiede due argomenti, il primo è lo spazio dei nomi XML e il secondo è un argomento facoltativo impostato per impostazione predefinita falso. Se il secondo argomento è impostato su TRUE, lo spazio dei nomi verrà trattato come un prefisso. Se FALSE, lo spazio dei nomi verrà trattato come lo spazio dei nomi dell'URL.

Il secondo approccio consiste nel leggere i nomi URI dal documento e utilizzarli quando si fa riferimento allo spazio dei nomi dell'elemento. Questo è in realtà il modo migliore per accedere agli elementi perché non è necessario essere codificati in un URI.

$namespaces = $languages ​​​​-> getNamespaces (true);
$dc = $lingue -> lang [ 1 ] -> bambini ($namespaces [ "dc" ] );

echo $dc -> creatore ;

Metodo OttieniSpazi dei nomi() restituisce un array di nomi di prefissi e i relativi URI associati. Richiede un parametro aggiuntivo che per impostazione predefinita è falso. Se lo installi come VERO, questo metodo restituirà i nomi utilizzati nei nodi padre e figlio. In caso contrario, trova gli spazi dei nomi utilizzati solo nel nodo padre.

Ora puoi scorrere l'elenco delle lingue in questo modo:

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

foreach ($lingue -> lang come $lang ) (
$dc = $lang -> figli ($ns [ "dc" ] ) ;
stampaf (
"

%s è apparso in %d ed è stato creato da %s .

" ,
$lang["nome"] ,
$lang -> apparso,
$dc -> creatore
) ;
}

Caso di studio: analisi di un canale video di YouTube

Diamo un'occhiata a un esempio che riceve un feed RSS da Canale Youtube e visualizza i collegamenti a tutti i video da esso. Per fare ciò, si prega di contattare il seguente indirizzo:

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

L'URL restituisce un elenco degli ultimi video del canale specificato in formato XML. Analizzeremo l'XML e otterremo le seguenti informazioni per ogni video:

  • Collegamento al filmato
  • Miniatura
  • Nome

Inizieremo cercando e caricando l'XML:

$canale = "NomeCanale" ;
$url = "http://gdata.youtube.com/feeds/api/users/". $canale. "/upload" ;
$xml = file_get_contents ($url);

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

Se guardi il feed XML, puoi vedere che ci sono diversi elementi lì. entità, ognuno dei quali memorizza informazioni dettagliate su un video specifico del canale. Ma utilizziamo solo le miniature delle immagini, l'indirizzo e il titolo del video. Questi tre elementi sono figli dell'elemento gruppo, che a sua volta è figlio di iscrizione:

>

>



Titolo... >

>

>

Esamineremo solo tutti gli elementi iscrizione ed estrarre le informazioni necessarie per ciascuno di essi. notare che giocatore, miniatura E titolo sono nello spazio dei nomi del supporto. Quindi, dobbiamo procedere come nell'esempio precedente. Otteniamo i nomi dal documento e utilizziamo lo spazio dei nomi quando ci riferiamo agli elementi.

foreach ($feed -> voce come $voce ) (
$gruppo = $entry -> bambini ($ns [ "media" ] ) ;
$gruppo = $gruppo -> gruppo ;
$thumbnail_attrs = $group -> miniatura [ 1 ] -> attributi ();
$image = $thumbnail_attrs ["url"] ;
$giocatore = $gruppo -> giocatore -> attributi ();
$link = $giocatore["url"] ;
$titolo = $gruppo -> titolo ;
stampaf ( "

" ,
$giocatore, $immagine, $titolo);
}

Conclusione

Ora che sai come usare SimpleXML per analizzare i dati XML, puoi migliorare le tue abilità analizzando diversi feed XML con diverse API. Ma è importante tenere presente che SimpleXML legge l'intero DOM in memoria, quindi se stai analizzando un set di dati di grandi dimensioni, potresti esaurire la memoria. Per saperne di più su SimpleXML leggi la documentazione.


In caso di domande, utilizzare il nostro

Extensible Markup Language XML è un insieme di regole per codificare i documenti in una forma leggibile dalla macchina. XML è un formato popolare per lo scambio di dati su Internet. I siti che aggiornano frequentemente il proprio contenuto, come siti di notizie o blog, spesso forniscono un feed XML in modo che i programmi esterni siano a conoscenza delle modifiche al contenuto. L'invio e l'analisi dei dati XML è un'attività comune per le applicazioni con una connessione di rete. Questa lezione spiega come analizzare i documenti XML e utilizzarne i dati.

Scelta di un analizzatore

Analisi del canale

Il primo passo nell'analisi di un feed è decidere a quali campi di dati sei interessato. Il parser estrae i campi dati e ignora tutto il resto.

Ecco lo snippet del canale che verrà analizzato nell'applicazione di esempio. Ogni post su StackOverflow.com appare nel feed come tag di ingresso, che contiene diversi tag nidificati:

domande più recenti contrassegnate con Android - Stack Overflow ... ... http://stackoverflow.com/q/9439999 0 Dov'è il mio file di dati? scogliera2310 http://stackoverflow.com/users/1128925 2012-02-25T00:30:54Z 2012-02-25T00:30:54Z

Ho un'applicazione che richiede un file di dati...

... ...

L'applicazione di esempio recupera i dati dal tag entry e dai relativi tag secondari title, link e summary.

Creazione di un'istanza del parser

Il passaggio successivo consiste nell'istanziare il parser e avviare il processo di analisi. In questo frammento, il parser viene inizializzato per non gestire gli spazi dei nomi e anche per utilizzare l'InputStream fornito come input. Il processo di parsing viene avviato con una chiamata a nextTag() e chiama il metodo readFeed(), che recupera ed elabora i dati a cui l'applicazione è interessata:

Public class StackOverflowXmlParser ( // Non usiamo namespace private static final String ns = null; public List parse(InputStream in) genera XmlPullParserException, IOException ( try ( XmlPullParser parser = Xml.newPullParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES , false); parser.setInput(in, null); parser.nextTag(); return readFeed(parser); ) finally ( in.close(); ) ) ... )

sottrarre canale

Il metodo readFeed() esegue l'effettivo lavoro di elaborazione del feed. Gli elementi contrassegnati con il tag "entry" sono il punto di partenza per l'elaborazione ricorsiva del canale. Se il tag successivo non è un tag di ingresso, viene saltato. Dopo che l'intero "feed" è stato elaborato in modo ricorsivo, readFeed() restituisce un elenco contenente le voci (compresi gli elementi di dati nidificati) recuperate dal feed. Questo elenco viene quindi restituito dal parser.

Elenco privato readFeed(XmlPullParser parser) genera XmlPullParserException, IOException ( Voci elenco = new ArrayList (); parser.require(XmlPullParser.START_TAG, ns, "feed"); while (parser.next() != XmlPullParser.END_TAG) ( se (parser.getEventType() != XmlPullParser.START_TAG) ( continue; ) String name = parser.getName(); // Inizia cercando il tag di ingresso if (name.equals("entry")) ( entries.add( readEntry(parser)); ) else ( skip(parser); ) ) restituisce voci; )

Analisi XML

I passaggi per analizzare il feed XML sono i seguenti:

Questo frammento mostra come il parser analizza la voce, il titolo, il collegamento e il riepilogo.

Classe statica pubblica Entry ( public final String title; public final String link; public final String summary; private Entry(String title, String summary, String link) ( this.title = title; this.summary = summary; this.link = link ; ) ) // Analizza il contenuto di una voce. Se incontra un titolo, un sommario o un tag di collegamento, passali // ai rispettivi metodi di "lettura" per l'elaborazione. Altrimenti, salta il tag. private Entry readEntry(XmlPullParser parser) genera XmlPullParserException, IOException ( parser.require(XmlPullParser.START_TAG, ns, "entry"); String title = null; String summary = null; String link = null; while (parser.next() ! = XmlPullParser.END_TAG) ( if (parser.getEventType() != XmlPullParser.START_TAG) ( continue; ) String name = parser.getName(); if (name.equals("title")) ( title = readTitle(parser) ; ) else if (name.equals("summary")) ( summary = readSummary(parser); ) else if (name.equals("link")) ( link = readLink(parser); ) else ( skip(parser) ; ) ) return new Entry(title, summary, link); ) // Processa i title tag nel feed. private String readTitle(XmlPullParser parser) genera IOException, XmlPullParserException ( parser.require(XmlPullParser.START_TAG, ns, "title"); String title = readText(parser); parser.require(XmlPullParser.END_TAG, ns, "title"); return title; ) // Elabora i tag di collegamento nel feed. private String readLink(XmlPullParser parser) genera IOException, XmlPullParserException ( String link = ""; parser.require(XmlPullParser.START_TAG, ns, "link"); String tag = parser.getName(); String relType = parser.getAttributeValue(null , "rel"); if (tag.equals("link")) ( if (relType.equals("alternate"))( link = parser.getAttributeValue(null, "href"); parser.nextTag(); ) ) parser.require(XmlPullParser.END_TAG, ns, "link"); link di ritorno; ) // Elabora i tag di riepilogo nel feed. private String readSummary(XmlPullParser parser) genera IOException, XmlPullParserException ( parser.require(XmlPullParser.START_TAG, ns, "summary"); String summary = readText(parser); parser.require(XmlPullParser.END_TAG, ns, "summary"); return summary; ) // Per i tag title e summary, estrae i loro valori di testo. private String readText(XmlPullParser parser) genera IOException, XmlPullParserException ( String result = ""; if (parser.next() == XmlPullParser.TEXT) ( result = parser.getText(); parser.nextTag(); ) return result; ) ... )

Salta gli elementi che non ti servono

In uno dei passaggi di analisi XML sopra descritti, il parser salta i tag che non ci interessano. Di seguito è riportato il codice del parser per il metodo skip():

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

Ecco come funziona:

  • Il metodo genera un'eccezione se l'evento corrente non è START_TAG .
  • Utilizza START_TAG e tutti gli eventi fino a END_TAG.
  • Per assicurarsi che si fermi all'END_TAG corretto e non al primo tag che incontra dopo l'START_TAG originale, tiene traccia della profondità di nidificazione.

Pertanto, se l'elemento corrente ha elementi nidificati, la profondità non sarà 0 fino a quando il parser non avrà elaborato tutti gli eventi tra l'START_TAG originale e il corrispondente END_TAG . Ad esempio, considera come salta il parser un elemento che ha 2 elementi nidificati, E :

  • Al primo passaggio attraverso il ciclo while, il tag successivo che il parser incontra dopo questo è il START_TAG per
  • Al secondo passaggio del ciclo while, il tag successivo che il parser incontra è END_TAG
  • Al terzo passaggio del ciclo while, il tag successivo che il parser incontra è START_TAG . Il valore della profondità viene aumentato a 2.
  • Al quarto passaggio del ciclo while, il tag successivo che il parser incontra è END_TAG. Il valore della profondità viene ridotto a 1.
  • Al quinto e ultimo passaggio del ciclo while, il tag successivo rilevato dal parser è END_TAG. Il valore della profondità scende a 0, a indicare ciò l'elemento è stato saltato con successo.

Elaborazione di dati XML

L'applicazione di esempio riceve e analizza il feed XML in un AsyncTask . L'elaborazione viene eseguita al di fuori del thread dell'interfaccia utente principale. Al termine dell'elaborazione, l'applicazione aggiorna l'interfaccia utente nell'attività principale (NetworkActivity).

Nello snippet seguente, il metodo loadPage() esegue le seguenti operazioni:

  • Inizializza una variabile stringa con un valore URL che punta a un feed XML.
  • Chiama new DownloadXmlTask().execute(url) se le impostazioni dell'utente e la connessione di rete lo consentono. Questo crea un nuovo oggetto DownloadXmlTask ​​​​(una sottoclasse AsyncTask) ed esegue il suo metodo execute(), che scarica e analizza il feed e restituisce un risultato di stringa da visualizzare nell'interfaccia utente.
public class NetworkActivity estende l'attività ( public static final String WIFI = "Wi-Fi"; public static final String ANY = "Qualsiasi"; private static final String URL = "http://stackoverflow.com/feeds/tag?tagnames=android&sort =newest"; // Se è presente una connessione Wi-Fi. private static boolean wifiConnected = false; // Se è presente una connessione mobile. private static boolean mobileConnected = false; // Se il display deve essere aggiornato. public static boolean refreshDisplay = true; public static String sPref = null; ... // Utilizza AsyncTask per scaricare il feed XML da stackoverflow.com. public void loadPage() ( if((sPref. equals(ANY)) && (wifiConnected || mobileConnected )) ( new DownloadXmlTask().execute(URL); ) else if ((sPref.equals(WIFI)) && (wifiConnected)) ( new DownloadXmlTask().execute(URL); ) else ( // mostra errore ) )
  • doInBackground() esegue il metodo loadXmlFromNetwork(). Passa l'URL del canale come parametro. Il metodo loadXmlFromNetwork() riceve ed elabora il canale. Al termine dell'elaborazione, restituisce la stringa risultante.
  • onPostExecute() accetta la stringa restituita e la visualizza nell'interfaccia utente.
// Implementazione di AsyncTask utilizzata per scaricare il feed XML da stackoverflow.com. classe privata DownloadXmlTask ​​estende 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 result) ( setContentView(R.layout.main); // Visualizza la stringa HTML nell'interfaccia utente tramite WebView WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.loadData(result, "text/html", null); ) )

Di seguito è riportato il metodo loadXmlFromNetwork() che viene chiamato da DownloadXmlTask ​​​​. Fa quanto segue:

  1. Crea un'istanza di StackOverflowXmlParser . Crea anche variabili per gli oggetti List Entry e title , url e summary , per archiviare i valori recuperati dal feed XML per quei campi.
  2. Chiama downloadUrl() , che scarica il feed e lo restituisce come InputStream .
  3. Utilizza StackOverflowXmlParser per analizzare InputStream . StackOverflowXmlParser popola le voci dell'elenco con i dati del feed.
  4. Elabora le voci List e combina i dati del feed con il markup HTML.
  5. Restituisce una stringa HTML che viene visualizzata nell'interfaccia utente dell'attività principale, AsyncTask nel metodo onPostExecute().
// Carica XML da stackoverflow.com, lo analizza e lo combina con // markup HTML. Restituisce una stringa HTML. private String loadXmlFromNetwork(String urlString) genera XmlPullParserException, IOException ( InputStream stream = null; // Crea un'istanza del parser StackOverflowXmlParser stackOverflowXmlParser = new StackOverflowXmlParser(); List voci = nulle; Titolo stringa = null; URL stringa = nullo; Riepilogo stringa = null; Calendario rightNow = Calendar.getInstance(); Formattatore DateFormat = new SimpleDateFormat("MMM dd h:mmaa"); // Controlla se l'utente ha impostato la preferenza per includere il testo di riepilogo SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); boolean pref = sharedPrefs.getBoolean("summaryPref", false); StringBuilder htmlString = new StringBuilder(); htmlString.append("

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

"); htmlString.append(" " + getResources().getString(R.string.updated) + " " + formatter.format(rightNow.getTime()) + ""); try ( stream = downloadUrl(urlString); entries = stackOverflowXmlParser.parse(stream); // Assicurati che InputStream sia chiuso dopo che l'app ha // finito di usarlo. ) finally ( if (stream != null) ( stream.close(); ) ) // StackOverflowXmlParser restituisce un elenco (chiamato "voci") di oggetti Entry. // Ogni oggetto Entry rappresenta un singolo post nel feed XML. // Questa sezione elabora l'elenco delle voci per combinare ogni voce con markup HTML. // Ogni voce viene visualizzata nell'interfaccia utente come collegamento che include facoltativamente // un riepilogo di testo. for (Voce voce: voci) ( htmlString. append("

" + voce.titolo + "

"); // Se l'utente imposta la preferenza per includere il testo di riepilogo, // lo aggiunge al display. if (pref) ( htmlString.append(entry.summary); ) ) return htmlString.toString(); ) // Data una rappresentazione di stringa di un URL, imposta una connessione e ottiene // un input stream.private InputStream downloadUrl(String urlString) genera IOException ( URL url = new URL(urlString); HttpURLConnection conn = (HttpURLConnection) url.openConnection() ; conn.setReadTimeout(10000 /* millisecondi */); conn.setConnectTimeout(15000 /* millisecondi */); conn.setRequestMethod("GET"); conn.setDoInput(true); // Avvia la query conn.connect( ); return conn.getInputStream(); )
la pubblicazione di questo articolo è consentita solo con un collegamento al sito dell'autore dell'articolo

In questo articolo, mostrerò un esempio di come analizzare un file XML di grandi dimensioni. Se al tuo server (hosting) non è vietato aumentare il tempo di esecuzione dello script, puoi analizzare un file XML del peso di almeno gigabyte, io personalmente ho analizzato solo file da ozone del peso di 450 megabyte.

Esistono due problemi durante l'analisi di file XML di grandi dimensioni:
1. Memoria insufficiente.
2. Il tempo allocato non è sufficiente per il funzionamento dello script.

Il secondo problema con il tempo può essere risolto se questo non è proibito dal server.
Ma il problema con la memoria è difficile da risolvere, anche se parliamo del tuo server, quindi spostare file da 500 megabyte non è molto semplice, e anche su hosting e su VDS semplicemente non puoi aumentare la memoria.

PHP ha diverse opzioni di elaborazione XML integrate: SimpleXML, DOM, SAX.
Tutte queste opzioni sono dettagliate in molti articoli di esempio, ma tutti gli esempi mostrano come lavorare con un documento XML completo.

Ecco un esempio, otteniamo un oggetto da un file XML

Ora puoi elaborare questo oggetto, MA...
Come puoi vedere, l'intero file XML viene letto in memoria, quindi tutto viene analizzato in un oggetto.
Cioè, tutti i dati entrano in memoria e se la memoria allocata non è sufficiente, lo script si interrompe.

Questa opzione non è adatta per l'elaborazione di file di grandi dimensioni, è necessario leggere il file riga per riga ed elaborare questi dati a turno.
Allo stesso tempo, viene effettuato anche il controllo di validità man mano che i dati vengono elaborati, quindi è necessario poter eseguire il rollback, ad esempio, eliminare tutto il database inserito nel caso di un file XML non valido, oppure effettuare due passa attraverso il file, prima letto per la validità, quindi letto per l'elaborazione dei dati.

Ecco un esempio teorico di analisi di un file XML di grandi dimensioni.
Questo script legge un carattere da un file, raccoglie questi dati in blocchi e li invia al parser XML.
Questo approccio risolve completamente il problema della memoria e non causa un carico, ma aggrava il problema nel tempo. Come provare a risolvere il problema nel tempo, leggi sotto.

Funzione webi_xml($file)
{

########
### funzione di gestione dei dati

{
stampa $dati ;
}
############################################



{
print $nome ;
print_r($attrs);
}


## funzione tag di chiusura
funzione endElement ($parser, $nome)
{
print $nome ;
}
############################################

($xml_parser, "dati");

// apri il file
$fp = fopen($file , "r" );

$perviy_vxod = 1 ; $dati = "" ;



{

$simvol = fgetc($fp); $dati .= $simvol ;


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


eco "

rottura;
}

$dati = "" ;
}
fchiudi($fp);

webi_xml("1.xml");

?>

In questo esempio, inserisco tutto in una funzione webi_xml () e la sua chiamata è visibile in fondo.
Lo script stesso è costituito da tre funzioni principali:
1. Una funzione che intercetta l'apertura del tag startElement()
2. Una funzione che rileva la chiusura del tag endElement()
3. E la funzione di ricezione dei dati data() .

Supponiamo che il contenuto del file 1.xml sia una ricetta



< title >pane semplice
< ingredient amount = "3" unit = "стакан" >Farina
< ingredient amount = "0.25" unit = "грамм" >Lievito
< ingredient amount = "1.5" unit = "стакан" >acqua calda
< ingredient amount = "1" unit = "чайная ложка" >Sale
< instructions >
< step > Mescolare tutti gli ingredienti e impastare bene.
< step > Coprire con un panno e lasciare per un'ora in una stanza calda.
< step > Impastare di nuovo, mettere su una teglia e mettere in forno.
< step > Visita il sito del sito


Iniziamo chiamando la funzione generica webi_xml("1.xml");
Inoltre in questa funzione, il parser si avvia e tutti i nomi dei tag vengono tradotti in maiuscolo in modo che tutti i tag abbiano lo stesso caso.

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

Ora specifichiamo quali funzioni lavoreranno per rilevare l'apertura del tag, la chiusura e l'elaborazione dei dati

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

Segue l'apertura del file specificato, itera sul file un carattere alla volta e ogni carattere viene aggiunto alla variabile stringa finché non viene trovato il carattere > .
Se questo è il primo vero accesso al file, tutto ciò che è superfluo all'inizio del file verrà eliminato lungo il percorso, tutto ciò che sta prima , questo è il tag con cui dovrebbe iniziare XML.
La prima volta che una variabile stringa raccoglierà una stringa

E invialo al parser
xml_parse ($xml_parser, $dati, feof ($fp));
Dopo aver elaborato i dati, la variabile stringa viene reimpostata e la raccolta dei dati in una stringa ricomincia e viene formata una stringa per la seconda volta

Nel terzo
</b><br>nel quarto <br><b>pane semplice

Si noti che la variabile stringa è sempre formata dal tag completato > e non è necessario inviare tag aperti e chiusi con dati al decompositore, ad esempio
pane semplice
È importante per questo gestore ottenere un intero tag ininterrotto, almeno un tag aperto e nel passaggio successivo un tag chiuso, o ottenere immediatamente 1000 righe del file, non importa, l'importante è che il tag non si rompe, per esempio

le>Pane semplice
Quindi è impossibile inviare i dati al gestore, perché il tag è rotto.
Puoi trovare il tuo metodo per inviare i dati al gestore, ad esempio raccogliere 1 megabyte di dati e inviarlo al gestore per aumentare la velocità, assicurati solo che i tag finiscano sempre e che i dati possano essere interrotti
Semplice</b><br><b>pane

Quindi, in parti, come desideri, puoi inviare file grande al gestore.

Ora diamo un'occhiata a come vengono elaborati questi dati e come ottenerli.

A partire dalla funzione dei tag di apertura startElement ($ parser , $name , $attrs )
Supponiamo che l'elaborazione abbia raggiunto la linea
< ingredient amount = "3" unit = "стакан" >Farina
Quindi all'interno della funzione la variabile $name sarà uguale a ingrediente ovvero il nome del tag aperto (l'argomento non è ancora arrivato alla chiusura del tag).
Anche in questo caso sarà disponibile un array di attributi di questo tag $attrs, in cui ci saranno dati importo = "3" e unità = "vetro".

Successivamente, i dati del tag aperto sono stati elaborati dalla funzione dati ($parser, $dati)
La variabile $data conterrà tutto quello che c'è tra il tag di apertura e quello di chiusura, nel nostro caso è il testo Muk

E l'elaborazione della nostra stringa da parte della funzione è completata endElement ($parser, $nome)
Questo è il nome del tag chiuso, nel nostro caso $name sarà uguale a ingrediente

E dopo, tutto è tornato al punto di partenza.

L'esempio precedente dimostra solo il principio dell'elaborazione XML, ma per un'applicazione reale deve essere finalizzato.
Di solito, devi analizzare XML di grandi dimensioni per inserire dati nel database e, per una corretta elaborazione dei dati, devi sapere a quale tag aperto appartengono i dati, a quale livello di annidamento dei tag e quali tag sono aperti nella gerarchia sopra. Con queste informazioni, è possibile elaborare correttamente il file senza problemi.
Per fare ciò, è necessario introdurre diverse variabili globali che raccolgono informazioni su tag aperti, nidificazione e dati.
Ecco un esempio che può essere utilizzato

Funzione webi_xml($file)
{
globale $ webi_depth ; // contatore per tenere traccia della profondità di annidamento
$webi_profondità = 0;
globale $ webi_tag_open ; // conterrà un array di open in questo momento tag
$webi_tag_open = array();
globale $ webi_data_temp ; // questo array conterrà i dati di un tag

####################################################
### funzione di gestione dei dati
funzione dati ($ parser , $ data )
{
globale $ webi_depth ;
globale $ webi_tag_open ;
globale $ webi_data_temp ;
// aggiunge dati all'array con annidamento e tag attualmente aperto
$webi_data_temp [ $webi_depth ][ $webi_tag_open [ $webi_depth ]][ "data" ].= $data ;
}
############################################

####################################################
### funzione tag di apertura
funzione startElement ($ parser , $name , $attrs )
{
globale $ webi_depth ;
globale $ webi_tag_open ;
globale $ webi_data_temp ;

// se il livello di annidamento non è già zero, allora un tag è già aperto
// e i dati da esso sono già nell'array, puoi elaborarli
se ($ webi_depth)
{




" ;

stampa"
" ;
print_r($webi_tag_open); // array di tag aperti
stampa"


" ;

// dopo aver elaborato i dati, cancellali per liberare memoria
unset($GLOBALS [ "webi_data_temp" ][ $webi_depth ]);
}

// ora l'apertura del tag successivo è iniziata e l'ulteriore elaborazione avverrà nel passaggio successivo
$webi_profondità++; // aumenta l'annidamento

$webi_tag_open [$webi_depth]= $nome; // aggiunge tag aperto all'array info
$webi_data_temp [ $webi_depth ][ $name ][ "attrs" ]= $attrs ; // ora aggiungi gli attributi del tag

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

#################################################
## funzione tag di chiusura
funzione endElement ($ parser , $ nome ) (
globale $ webi_depth ;
globale $ webi_tag_open ;
globale $ webi_data_temp ;

// l'elaborazione dei dati inizia qui, ad esempio, l'aggiunta al database, il salvataggio in un file, ecc.
// $webi_tag_open contiene una catena di tag aperti per livello di nidificazione
// ad esempio $webi_tag_open[$webi_depth] contiene il nome del tag aperto le cui informazioni sono attualmente in fase di elaborazione
// Livello di nidificazione tag $webi_depth
// $webi_data_temp[$webi_depth][$webi_tag_open[$webi_depth]]["attrs"] array di attributi di tag
// $webi_data_temp[$webi_depth][$webi_tag_open[$webi_depth]]["data"] dati dei tag

Stampa "dati". $webi_tag_open [ $webi_depth ]. "--" .($webi_data_temp [ $webi_depth ][ $webi_tag_open [ $webi_depth ]][ "dati" ]). "
" ;
print_r ($webi_data_temp [ $webi_depth ][ $webi_tag_open [ $webi_depth ]][ "attrs" ]);
stampa"
" ;
print_r($webi_tag_open);
stampa"


" ;

Unset($GLOBALS [ "webi_data_temp" ]); // dopo aver elaborato i dati, cancella l'array con i dati nel loro insieme, poiché il tag è stato chiuso
unset($GLOBALS [ "webi_tag_open" ][ $webi_depth ]); // rimuove le informazioni su questo tag aperto... poiché è stato chiuso

$webi_profondità --; // riduce l'annidamento
}
############################################

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

// specifica quali funzioni funzioneranno durante l'apertura e la chiusura dei tag
xml_set_element_handler($xml_parser , "startElement" , "endElement" );

// specifica una funzione per lavorare con i dati
xml_set_character_data_handler($xml_parser, "dati");

// apri il file
$fp = fopen($file , "r" );

$perviy_vxod = 1 ; // flag per il controllo del primo input nel file
$dati = "" ; // qui raccogliamo parti dei dati dal file e li inviamo al parser xml

// ciclo fino alla fine del file trovato
while (! feof ($fp ) e $fp )
{
$simvol = fgetc($fp); // legge un carattere dal file
$dati .= $simvol ; // aggiunge questo carattere ai dati da inviare

// se il carattere non è il tag di fine, torna all'inizio del ciclo e aggiungi un altro carattere ai dati, e così via finché non viene trovato il tag di fine
if($simvol != ">" ) ( continua;)
// se è stato trovato il tag di chiusura, ora invia questi dati raccolti all'elaborazione

// controlla se questa è la prima voce nel file, quindi cancella tutto prima del tag// poiché a volte potrebbero esserci dei rifiuti prima dell'inizio dell'XML (editor goffi o il file è stato ricevuto dallo script da un altro server)
if($perviy_vxod ) ( $dati = strstr ($dati , "

// ora inseriamo i dati nel parser xml
if (! xml_parse ($xml_parser , $data , feof ($fp ))) (

// qui puoi elaborare e ottenere errori per la validità...
// non appena si verifica un errore, l'analisi si interrompe
eco "
Errore XML: " .xml_error_string (xml_get_error_code ($xml_parser ));
echo "alla linea" . xml_get_current_line_number($xml_parser );
rottura;
}

// dopo l'analisi, eliminiamo i dati raccolti per il passaggio successivo del ciclo.
$dati = "" ;
}
fchiudi($fp);
xml_parser_free($xml_parser );
// elimina le variabili globali
unset($GLOBALS [ "webi_depth" ]);
unset($GLOBALS [ "webi_tag_open" ]);
unset($GLOBALS [ "webi_data_temp" ]);

webi_xml("1.xml");

?>

L'intero esempio è stato accompagnato da commenti, ora prova e sperimenta.
Si noti che nella funzione di manipolazione dei dati, i dati non vengono semplicemente inseriti nell'array, ma vengono aggiunti utilizzando " .=" poiché i dati potrebbero non presentarsi in una forma completa e se esegui solo un incarico, di volta in volta riceverai i dati in blocchi.

Bene, questo è tutto, ora ci sarà memoria sufficiente durante l'elaborazione di un file di qualsiasi dimensione, ma il tempo di esecuzione dello script può essere aumentato in diversi modi.
Inserisci una funzione all'inizio dello script
set_time_limit(6000);
O
ini_set("tempo_max_esecuzione" , "6000" );

Oppure aggiungi del testo al file .htaccess
php_value max_execution_time 6000

Questi esempi aumenteranno il tempo di esecuzione dello script a 6000 secondi.
È possibile aumentare il tempo in questo modo solo in modalità provvisoria.

Se hai accesso alla modifica di php.ini puoi aumentare il tempo con
max_execution_time = 6000

Ad esempio, sull'hosting masterhost, al momento della stesura di questo documento, è vietato aumentare il tempo di script, nonostante sia disabilitato modalità sicura, ma se sei un professionista, puoi creare il tuo php sul masterhost, ma questo non è in questo articolo.

Ora studieremo come lavorare con XML. XML è un formato per lo scambio di dati tra siti. È molto simile all'HTML, solo XML consente i propri tag e attributi.

Perché XML è necessario per l'analisi? A volte capita che il sito che devi analizzare abbia un'API che ti permetta di ottenere ciò che desideri senza troppi sforzi. Pertanto, consiglio immediatamente: prima di analizzare il sito, controlla se ha un'API.

Cos'è un'API? Si tratta di un insieme di funzioni con le quali è possibile inviare una richiesta a questo sito ed ottenere la risposta desiderata. Questa risposta arriva molto spesso in formato XML. Quindi iniziamo a studiarlo.

Lavorare con XML in PHP

Diciamo che hai XML. Può trovarsi in una stringa, memorizzato in un file o offerto su richiesta a un URL specifico.

Lascia che l'XML sia memorizzato in una stringa. In questo caso, è necessario creare un oggetto da questa linea utilizzando nuovo SimpleXMLElement:

$str = " Kolja 25 1000 "; $xml = new SimpleXMLElement($str);

Ora abbiamo in una variabile $xml viene memorizzato un oggetto con XML analizzato. Accedendo alle proprietà di questo oggetto è possibile accedere al contenuto dei tag XML. Come esattamente - analizzeremo un po 'più in basso.

Se l'XML è memorizzato in un file o restituito accedendo a un URL (che è il caso più frequente), allora dovresti usare la funzione simplexml_load_file che fa lo stesso oggetto $xml:

Kolja 25 1000

$xml = simplexml_load_file(percorso file o url);

Metodi di lavoro

Negli esempi seguenti, il nostro XML è memorizzato in un file o in un URL.

Sia dato il seguente XML:

Kolja 25 1000

Prendiamo il nome, l'età e lo stipendio di un dipendente:

$xml = simplexml_load_file(percorso file o url); echo $xml->nome; //visualizza "Kolya" echo $xml->età; //emette 25 echo $xml->stipendio; // restituisce 1000

Come puoi vedere, l'oggetto $xml ha proprietà corrispondenti ai tag.

Potresti aver notato che il tag non compare da nessuna parte in circolazione. Questo perché è il tag root. Puoi rinominarlo, ad esempio, in - e nulla cambierà:

Kolja 25 1000

$xml = simplexml_load_file(percorso file o url); echo $xml->nome; //visualizza "Kolya" echo $xml->età; //emette 25 echo $xml->stipendio; // restituisce 1000

Può esserci un solo tag root in XML, proprio come il tag root in semplice HTML.

Modifichiamo un po' il nostro XML:

Kolja 25 1000

In questo caso, otteniamo una catena di chiamate:

$xml = simplexml_load_file(percorso file o url); echo $xml->lavoratore->nome; //visualizza "Kolya" echo $xml->lavoratore->età; //output 25 echo $xml->lavoratore->salario; // restituisce 1000

Lavorare con gli attributi

Lascia che alcuni dati vengano memorizzati negli attributi:

Numero 1

$xml = simplexml_load_file(percorso file o url); echo $xml->lavoratore["nome"]; //visualizza "Kolya" echo $xml->lavoratore["età"]; //emette 25 echo $xml->lavoratore["salario"]; //emette 1000 echo $xml->worker; //stampa "Numero 1"

Tag con trattini

In XML sono consentiti i tag (e gli attributi) con un trattino. In questo caso, si accede a tali tag in questo modo:

Kolja Ivanov

$xml = simplexml_load_file(percorso file o url); echo $xml->lavoratore->(nome); //visualizza "Kolya" echo $xml->lavoratore->(cognome); //visualizza "Ivanov"

Iterazione del ciclo

Lascia che ora non abbiamo un lavoratore, ma diversi. In questo caso, possiamo iterare sul nostro oggetto con un ciclo foreach:

Kolja 25 1000 Vasia 26 2000 Peter 27 3000

$xml = simplexml_load_file(percorso file o url); foreach ($xml as $lavoratore) ( echo $lavoratore->nome; //stampa "Kolya", "Vasya", "Petya" )

Dall'oggetto all'array normale

Se non ti senti a tuo agio a lavorare con un oggetto, puoi convertirlo in un normale array PHP con il seguente trucco:

$xml = simplexml_load_file(percorso file o url); var_dump(json_decode(json_encode($xml), true));

Maggiori informazioni

Analisi basata su sitemap.xml

Spesso un sito ha un file sitemap.xml. Questo file memorizza i collegamenti a tutte le pagine del sito per comodità di indicizzazione da parte dei motori di ricerca (l'indicizzazione è, infatti, l'analisi del sito da parte di Yandex e Google).

In generale, non dovremmo preoccuparci molto del motivo per cui questo file è necessario, l'importante è che se esiste, non puoi scalare le pagine del sito con metodi complicati, ma semplicemente utilizzare questo file.

Come verificare la presenza di questo file: analizziamo il sito site.ru, quindi facciamo riferimento a site.ru/sitemap.xml nel browser: se vedi qualcosa, allora è lì e se non lo vedi, allora ahimè.

Se esiste una mappa del sito, contiene collegamenti a tutte le pagine del sito in formato XML. Sentiti libero di prendere questo XML, analizzarlo, separare i collegamenti alle pagine di cui hai bisogno in qualsiasi modo conveniente per te (ad esempio, analizzando l'URL descritto nel metodo spider).

Di conseguenza, ottieni un elenco di collegamenti per l'analisi, non resta che andare su di essi e analizzare il contenuto di cui hai bisogno.

Maggiori informazioni sul dispositivo sitemap.xml su wikipedia.

Cosa fai dopo:

Inizia a risolvere i problemi al seguente link: compiti per la lezione.

Quando tutto è deciso, vai allo studio di un nuovo argomento.

Se noti un errore, seleziona una parte di testo e premi Ctrl + Invio
CONDIVIDERE: