Ablakok.  Vírusok.  Jegyzetfüzetek.  Internet.  hivatal.  Segédprogramok.  Drivers

Az XML elemzése lényegében azt jelenti, hogy végigmegyünk egy XML dokumentumon, és visszaadjuk a megfelelő adatokat. És bár minden több A webszolgáltatások JSON formátumban adják vissza az adatokat, de a legtöbb továbbra is XML-t használ, ezért fontos elsajátítani XML elemzés ha az elérhető API-k teljes skáláját szeretné használni.

A kiterjesztés használata SimpleXML a PHP-ben, amelyet a PHP 5.0-ban adtak hozzá, az XML-lel való munkavégzés nagyon könnyű és egyszerű. Ebben a cikkben megmutatom, hogyan kell csinálni.

Használati alapok

Kezdjük a következő példával nyelvek.xml:


>

> 1972>
> Dennis Ritchie >
>

> 1995>
> Rasmus Lerdorf >
>

> 1995>
> James Gosling >
>
>

Ez az XML-dokumentum a programozási nyelvek listáját tartalmazza, néhány információval az egyes nyelvekről: a megvalósítás éve és a készítő neve.

Az első lépés az XML betöltése a függvények használatával simplexml_load_file(), vagy simplexml_load_string(). Ahogy a függvények neve is sugallja, az első egy fájlból, a második pedig egy karakterláncból tölti be az XML-t.

Mindkét függvény beolvassa a teljes DOM-fát a memóriába, és visszaad egy objektumot SimpleXMLElement. A fenti példában az objektum a $languages ​​változóban van tárolva. Használhat funkciókat var_dump() vagy print_r() hogy részletes információkat kapjon a visszaküldött objektumról, ha úgy tetszik.

SimpleXMLElement objektum
[lang] => Tömb
[ 0 ] => SimpleXMLElementObject
[@attributes] => Tömb
[név] => C
[megjelent] => 1972
[ alkotó] => Dennis Ritchie
[ 1 ] => SimpleXMLElement objektum
[@attributes] => Tömb
[név] => PHP
[megjelent] => 1995
[ alkotó] => Rasmus Lerdorf
[ 2 ] => SimpleXMLElement objektum
[@attributes] => Tömb
[név] => Java
[megjelent] => 1995
[ alkotó] => James Gosling
)
)

Ez az XML tartalmazza a gyökérelemet nyelvek, amely három elemet tartalmaz lang. Minden tömbelem egy elemnek felel meg nyelv egy XML dokumentumban.

Egy objektum tulajdonságait az operátor segítségével érheti el -> . Például a $languages->lang egy SimpleXMLElement objektumot ad vissza, amely megfelel az első elemnek nyelv. Ez az objektum két tulajdonságot tartalmaz: megjelent és létrehozó.

$languages ​​​​-> lang [ 0 ] -> megjelent ;
$languages ​​​​-> lang [ 0 ] -> creator ;

A nyelvek listájának megjelenítése és tulajdonságaik megjelenítése nagyon egyszerű szabványos hurokkal, mint pl az egyes.

foreach ($languages> -> lang mint $lang ) (
printf (
"" ,
$lang["név"] ,
$lang -> megjelent ,
$lang -> alkotó
) ;
}

Figyelje meg, hogyan jutottam hozzá a lang elem attribútumnevéhez, hogy megkapjam a nyelv nevét. Így elérheti a SimpleXMLElement objektumként ábrázolt elem bármely attribútumait.

Névterekkel való munka

A különféle webszolgáltatások XML-ével való munka során gyakran találkozhat elemnévterekkel. Változtassuk meg nyelvek.xml hogy példát mutassunk a névtér használatára:



xmlns:dc =>

> 1972>
> Dennis Ritchie >
>

> 1995>
> Rasmus Lerdorf >
>

> 1995>
> James Gosling >
>
>

Most elem Teremtő névtérbe helyezve dc, amely a http://purl.org/dc/elements/1.1/ címre mutat. Ha megpróbálja kinyomtatni a nyelvi alkotókat a korábbi kódunkkal, az nem fog működni. Az elemek névtereinek olvasásához a következő módszerek egyikét kell használnia.

Az első megközelítés az, hogy az URI-neveket közvetlenül a kódban használjuk, amikor az elem névterére hivatkozunk. A következő példa bemutatja, hogyan történik ez:

$dc = $nyelvek-> lang [1] -> gyermek( "http://purl.org/dc/elements/1.1/") ;
echo $dc -> creator ;

Módszer gyermekek() névteret vesz, és előtaggal kezdődő gyermekelemeket ad vissza. Két argumentumra van szükség, az első az XML névtér, a második pedig egy opcionális argumentum, amely alapértelmezés szerint az hamis. Ha a második argumentum értéke IGAZ, a névteret előtagként kezeli a rendszer. Ha FALSE, akkor a névteret az URL névtérként kezeli a rendszer.

A második megközelítés az URI-nevek beolvasása a dokumentumból, és az elem névterére történő hivatkozáskor használja őket. Valójában ez a legjobb módja az elemek elérésének, mert nem kell URI-ba kódolni.

$namespaces = $languages> -> getNamespaces (igaz) ;
$dc = $languages ​​​​-> lang [ 1 ] -> children ($namespaces [ "dc" ] ) ;

echo $dc -> creator ;

Módszer GetNamespaces() előtagnevek és a hozzájuk tartozó URI-k tömbjét adja vissza. Szükség van egy további paraméterre, amely az alapértelmezett hamis. Ha telepíti, mint igaz, akkor ez a metódus a szülő és gyermek csomópontokban használt neveket adja vissza. Ellenkező esetben csak a szülőcsomópontban használt névtereket találja meg.

Most ismételheti a nyelvek listáját, így:

$languages ​​​​= simplexml_load_file ("languages.xml" ) ;
$ns = $nyelvek -> getNamespaces (igaz) ;

foreach ($languages> -> lang mint $lang ) (
$dc = $lang -> gyermek ($ns [ "dc" ] ) ;
printf (
"

%s megjelent itt: %d, és %s hozta létre.

" ,
$lang["név"] ,
$lang -> megjelent ,
$dc -> alkotó
) ;
}

Esettanulmány – YouTube-videócsatorna elemzése

Nézzünk egy példát, amelytől RSS-hírcsatorna érkezik YouTube csatornaés megjeleníti az összes videó linkjét. Ehhez vegye fel a kapcsolatot az alábbi címen:

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

Az URL az adott csatorna legújabb videóinak listáját adja vissza XML formátumban. Elemezzük az XML-t, és minden videóhoz megkapjuk a következő információkat:

  • Link a videóhoz
  • Miniatűr
  • Név

Kezdjük az XML keresésével és betöltésével:

$channel = "Csatornanév" ;
$url = "http://gdata.youtube.com/feeds/api/users/". $csatorna. "/feltöltések" ;
$xml = file_get_contents ($url ) ;

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

Ha megnézed az XML feedet, láthatod, hogy több elem is van benne. entitás, amelyek mindegyike részletes információkat tárol a csatorna adott videójáról. De csak képek miniatűröket, videó címét és címét használjuk. Ez a három elem az elem gyermeke csoport, ami viszont gyermeke belépés:

>

>



Cím... >

>

>

Csak végigmegyünk az összes elemen belépés, és mindegyikhez kinyerjük a szükséges információkat. vegye figyelembe, hogy játékos, miniatűrÉs cím a média névtérben vannak. Így az előző példában leírtak szerint kell eljárnunk. A neveket a dokumentumból kapjuk, és a névteret használjuk, amikor az elemekre hivatkozunk.

foreach ($feed -> bejegyzés mint $entry ) (
$group = $bejegyzés -> gyermek ($ns [ "media" ] ) ;
$csoport = $csoport -> csoport ;
$thumbnail_attrs = $csoport -> thumbnail [ 1 ] -> attribútumok () ;
$image = $thumbnail_attrs [ "url" ] ;
$lejátszó = $csoport -> játékos -> attribútumok () ;
$link = $lejátszó["url"] ;
$cím = $csoport -> cím ;
printf ( "

" ,
$lejátszó , $kép , $cím ) ;
}

Következtetés

Most, hogy tudja, hogyan kell használni SimpleXML Az XML adatok elemzéséhez fejlesztheti készségeit a különböző XML feedek különböző API-kkal történő elemzésével. Fontos azonban észben tartani, hogy a SimpleXML a teljes DOM-ot beolvassa a memóriába, így ha nagy adatkészletet elemez, elfogyhat a memória. Ha többet szeretne megtudni a SimpleXML-ről, olvassa el a dokumentációt.


Ha kérdése van, kérjük, használja a mi

Az Extensible Markup Language XML a dokumentumok géppel olvasható formában történő kódolására szolgáló szabályok összessége. Az XML az internetes adatcsere népszerű formátuma. A tartalmukat gyakran frissítő webhelyek, például híroldalak vagy blogok gyakran biztosítanak XML-hírcsatornát, hogy a külső programok értesüljenek a tartalomváltozásokról. Az XML adatok küldése és elemzése gyakori feladat a hálózati kapcsolattal rendelkező alkalmazásoknál. Ez a lecke elmagyarázza, hogyan kell XML-dokumentumokat elemezni és felhasználni az adataikat.

Az elemző kiválasztása

Csatornaelemzés

A hírcsatorna elemzésének első lépése annak eldöntése, hogy mely adatmezők érdeklik. Az elemző kivonja a megadott mezőket, és figyelmen kívül hagy minden mást.

Itt látható a csatornarészlet, amelyet a mintaalkalmazásban elemezni fog. A StackOverflow.com minden bejegyzése bejegyzéscímkeként jelenik meg a hírfolyamban, amely több beágyazott címkét tartalmaz:

android címkével ellátott legújabb kérdések - Stack Overflow ... ... http://stackoverflow.com/q/9439999 0 Hol van az adatállományom? szikla2310 http://stackoverflow.com/users/1128925 2012-02-25T00:30:54Z 2012-02-25T00:30:54Z

Van egy alkalmazásom, amelyhez adatfájl szükséges...

... ...

A példaalkalmazás lekéri az adatokat a bejegyzés címkéjéből és annak cím, hivatkozás és összegzés alcímkéiből.

Az elemző példányának létrehozása

A következő lépés az elemző példányosítása és az elemzési folyamat elindítása. Ebben a kódrészletben az elemző úgy van inicializálva, hogy ne kezelje a névtereket, és a megadott InputStream-et használja bemenetként. Az elemzési folyamat a nextTag() meghívásával indul, és meghívja a readFeed() metódust, amely lekéri és feldolgozza az alkalmazást érdeklő adatokat:

Nyilvános osztály StackOverflowXmlParser ( // Nem használunk névtereket private static final String ns = null; public List parse(InputStream in) XmlPullParserException, IOException ( próbálja meg ( XmlPullParser parser = Xml.newPullParser();); parser.set.set. , false); parser.setInput(in, null); parser.nextTag(); return readFeed(elemző); ) végül (in.close(); ) ) ... )

csatorna kivonása

A readFeed() metódus végzi el az adatfolyam feldolgozásának tényleges munkáját. Az "entry" címkével jelölt elemek jelentik a rekurzív csatornafeldolgozás kiindulópontját. Ha a következő címke nem belépési címke, akkor a rendszer kihagyja. A teljes "hírcsatorna" rekurzív feldolgozása után a readFeed() egy listát ad vissza, amely tartalmazza a hírfolyamból lekért bejegyzéseket (beleértve a beágyazott adatelemeket is). Ezt a listát az elemző visszaadja.

Private List readFeed(XmlPullParser parser) az XmlPullParserException, IOException (listabejegyzések = new ArrayList (); parser.require(XmlPullParser.START_TAG, ns, "feed"); while (parser.next() != XmlPullParser) (if. (parser.getEventType() != XmlPullParser.START_TAG) ( folytatás; ) String name = parser.getName(); // Az if (name.equals("entry") bejegyzési címkével kezdődik) ( entries.add( readEntry(elemző)); ) else ( skip(parser); ) ) adja vissza a bejegyzéseket; )

XML elemzése

Az XML-hírcsatorna elemzésének lépései a következők:

Ez a részlet megmutatja, hogy az elemző hogyan elemzi a bejegyzést, a címet, a hivatkozást és az összefoglalót.

Nyilvános statikus osztály Bejegyzés ( publikus végleges Karakterlánc címe; publikus végleges Karakterlánc hivatkozás; nyilvános végleges Karakterlánc összefoglaló ; ) ) // Egy bejegyzés tartalmát elemzi. Ha címet, összefoglalót vagy hivatkozási címkét talál, adja át // a megfelelő "olvasási" metódusuknak a feldolgozáshoz. Ellenkező esetben hagyja ki a címkét. private Entry readEntry(XmlPullParser parser) 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) ( folytatás; ) Karakterlánc neve = parser.getName(); if (name.equals("title")) ( title = readTitle(parser) ; ) else if (name.equals("összefoglaló")) ( summary = readSummary(parser); ) else if (name.equals("link")) ( link = readLink(elemző); ) else ( skip(parser) ; ) ) return new Entry(cím, összefoglaló, link); ) // Feldolgozza a címcímkéket a hírfolyamban. private String readTitle(XmlPullParser parser) IOException, XmlPullParserException ( parser.require(XmlPullParser.START_TAG, ns, "title"); String title = readText(parser); parser.require(XmlPullParser.END_TAG, n) parancsot return title; ) // Feldolgozza a linkcímkéket a hírfolyamban. private String readLink(XmlPullParser parser) IOException, XmlPullParserException (String link = ""; parser.require(XmlPullParser.START_TAG, ns, "link"); String tag = parser.getName(); String relType = parser.getAttributeValue , "rel"); if (tag.equals("link")) (if (relType.equals("alternate"))( link = parser.getAttributeValue(null, "href"); parser.nextTag(); ) ) parser.require(XmlPullParser.END_TAG, ns, "link"); return link; ) // Feldolgozza az összefoglaló címkéket a hírfolyamban. private String readSummary(XmlPullParser parser) IOException, XmlPullParserException ( parser.require(XmlPullParser.START_TAG, ns, "summary"); String summary = readText(parser); parser.require(XmlPullParser.END_TAG, n); return summary; ) // A title és summary címkék szöveges értékeit kivonja. private String readText(XmlPullParser elemző) IOException, XmlPullParserException ( String result = ""; if (parser.next() == XmlPullParser.TEXT) ( result = parser.getText(); parser.nextTag(); ) eredményt ad vissza; ) ... )

Hagyja ki azokat a tárgyakat, amelyekre nincs szüksége

A fent leírt XML-elemzési lépések egyikében az elemző kihagyja azokat a címkéket, amelyekre nem vagyunk kíváncsiak. Alább látható a skip() metódus elemző kódja:

A privát void skip(XmlPullParser elemző) az XmlPullParserException, IOException paramétert dobja ( if (parser.getEventType() != XmlPullParser.START_TAG) ( új IllegalStateException(); ) int mélység = 1; while (depth != 0) ( kapcsoló next()) ( XmlPullParser eset.END_TAG: mélység--; törés; XmlPullParser kisbetű.START_TAG: mélység++; törés; ) ) )

Így működik:

  • A metódus kivételt dob, ha az aktuális esemény nem START_TAG.
  • Felhasználja START_TAG és az összes eseményt END_TAG-ig.
  • Annak biztosítása érdekében, hogy a megfelelő END_TAG-nál álljon meg, és ne az eredeti START_TAG után talált első címkénél, nyomon követi a beágyazási mélységet.

Így, ha az aktuális elem beágyazott elemeket tartalmaz, a mélység nem lesz 0, amíg az elemző fel nem dolgozott minden eseményt az eredeti START_TAG és a megfelelő END_TAG között. Vegyük például, hogyan ugrik az elemző egy elem, amely 2 beágyazott elemet tartalmaz, És :

  • A while cikluson való első áthaladáskor a következő címke, amellyel az elemző találkozik ez a START_TAG ehhez
  • A while ciklus második áthaladásakor a következő címke, amellyel az elemző találkozik, az END_TAG
  • A while ciklus harmadik lépésében a következő címke, amellyel az elemző találkozik, a START_TAG . A mélység értéke 2-re nő.
  • A while ciklus negyedik lépésénél a következő címke, amellyel az elemző találkozik, az END_TAG. A mélység értéke 1-re csökken.
  • Az ötödik és egyben utolsó lépésben a while cikluson a következő címke, amellyel az elemző találkozik, az END_TAG. A mélység értéke 0-ra csökken, jelezve, hogy az elem sikeresen kimaradt.

XML adatok feldolgozása

A példaalkalmazás fogadja és elemzi az XML-hírcsatornát egy AsyncTask-ban. A feldolgozás a fő felhasználói felületen kívül történik. A feldolgozás befejeztével az alkalmazás frissíti a felhasználói felületet a fő tevékenységben (NetworkActivity).

Az alábbi részletben a loadPage() metódus a következőket teszi:

  • Inicializál egy karakterlánc-változót, amelynek URL-értéke XML-hírcsatornára mutat.
  • Meghívja az új DownloadXmlTask().execute(url) függvényt, ha a felhasználó beállításai és a hálózati kapcsolat lehetővé teszik. Ez létrehoz egy új DownloadXmlTask ​​objektumot (egy AsyncTask alosztályt), és végrehajtja az execute() metódust, amely letölti és elemzi a hírfolyamot, és egy karakterlánc eredményt ad vissza, amelyet a felhasználói felületen kell megjeleníteni.
public class A NetworkActivity kiterjeszti az aktivitást ( nyilvános statikus végleges String WIFI = "Wi-Fi"; public static final String ANY = "Bármilyen"; privát statikus végső karakterlánc URL = "http://stackoverflow.com/feeds/tag?tagnames=android&sort =newest"; // Van-e Wi-Fi kapcsolat. private static logikai érték wifiConnected = false; // Van-e mobil kapcsolat refreshDisplay = true; public static String sPref = null; ... // Az AsyncTask segítségével letölti az XML feedet a stackoverflow.com webhelyről. public void loadPage() ( if((sPref. equals(ANY)) && (wifiConnected || mobileConnected )) ( new DownloadXmlTask().execute(URL); ) else if ((sPref.equals(WIFI)) && (wifiConnected)) ( new DownloadXmlTask().execute(URL); ) else ( // hiba megjelenítése ) )
  • A doInBackground() végrehajtja a loadXmlFromNetwork() metódust. Paraméterként adja át a csatorna URL-címét. A loadXmlFromNetwork() metódus fogadja és feldolgozza a csatornát. Amikor befejezi a feldolgozást, visszaküldi a kapott karakterláncot.
  • Az onPostExecute() veszi a visszaadott karakterláncot, és megjeleníti a felhasználói felületen.
// Az AsyncTask megvalósítása az XML-hírcsatorna letöltéséhez a stackoverflow.com webhelyről. privát osztály A DownloadXmlTask ​​​​kibővíti az AsyncTask-ot ( @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); // Megjeleníti a HTML karakterláncot a felhasználói felületen egy WebView WebView WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.loadData(eredmény, "text/html", null); ) )

Az alábbiakban látható a loadXmlFromNetwork() metódus, amelyet a DownloadXmlTask-ból hívnak meg. A következőket teszi:

  1. Létrehozza a StackOverflowXmlParser példányát. Változókat hoz létre a List Entry objektumokhoz, valamint a címhez, url-hez és összegzéshez, hogy tárolja az XML-hírcsatornából lekért értékeket ezekhez a mezőkhöz.
  2. Meghívja a downloadUrl() függvényt, amely letölti a hírfolyamot, és InputStreamként adja vissza.
  3. A StackOverflowXmlParser segítségével elemzi az InputStream . A StackOverflowXmlParser feltölti a listabejegyzéseket a feedből származó adatokkal.
  4. Feldolgozza a Lista bejegyzéseket, és egyesíti a feedadatokat a HTML-jelöléssel.
  5. Egy HTML-karakterláncot ad vissza, amely a fő tevékenység, az AsyncTask felhasználói felületén jelenik meg az onPostExecute() metódusban.
// XML-t tölt fel a stackoverflow.com webhelyről, elemzi, és kombinálja a // HTML-jelöléssel. HTML karakterláncot ad vissza. private String loadXmlFromNetwork(String urlString) XmlPullParserException, IOException ( InputStream stream = null; // Az elemző példányosítása StackOverflowXmlParser stackOverflowXmlParser = new StackOverflowXmlParser(); Lista bejegyzések = null; String title = null; String url = null; Karakterlánc összegzése = null; Calendar rightNow = Calendar.getInstance(); DateFormat formatter = new SimpleDateFormat("MMM dd h:mmaa"); // Ellenőrzi, hogy a felhasználó beállította-e összefoglaló szöveget a beállításban 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); bejegyzések = stackOverflowXmlParser.parse(stream); // Győződjön meg arról, hogy az InputStream be van zárva, miután az alkalmazás // befejezte a használatát. ) végül ( if (stream != null) ( stream.close(); ) ) // A StackOverflowXmlParser egy listát (úgynevezett "bejegyzéseket") ad vissza az Entry objektumokról. // Minden Entry objektum egyetlen bejegyzést jelent az XML feedben. // Ez a szakasz feldolgozza a bejegyzéslistát az egyes elemek kombinálásához. bejegyzés HTML-jelöléssel. // Minden bejegyzés hivatkozásként jelenik meg a felhasználói felületen, amely opcionálisan // tartalmaz egy szöveges összefoglalót. for (Bejegyzés: bejegyzések) ( htmlString. append("

" + bejegyzés.cím + "

"); // Ha a felhasználó úgy állítja be az összefoglaló szöveget, // hozzáadja a megjelenítéshez. if (pref) ( htmlString.append(entry.summary); ) ) return htmlString.toString(); ) // Adott egy URL karakterlánc-reprezentációja, létrehoz egy kapcsolatot, és // kap egy bemeneti adatfolyamot.private InputStream downloadUrl(String urlString) IOExceptiont dob ​​( URL url = new URL(urlString); HttpURLConnection conn = (HttpURLConnection) url(.openConnection ; conn.setReadTimeout(10000 /* ezredmásodperc */); conn.setConnectTimeout(15000 /* ezredmásodperc */); conn.setRequestMethod("GET"); conn.setDoInput(true); // Elindítja a conn.connect( ); return conn.getInputStream(); )
A cikk közzététele csak a cikk szerzőjének webhelyére mutató hivatkozással engedélyezett

Ebben a cikkben egy példát mutatok be egy nagy XML-fájl elemzésére. Ha a szerverednek (hostingnek) nincs tiltva a szkript futási idejének növelése, akkor legalább gigabájt súlyú XML fájlt is elemezhetsz, én személy szerint csak a 450 megabájt súlyú ózon fájlokat elemeztem.

Két probléma adódik a nagy XML-fájlok elemzésekor:
1. Nincs elég memória.
2. Nincs elegendő idő a szkript működéséhez.

A második idővel kapcsolatos probléma megoldható, ha ezt nem tiltja a szerver.
De a memória problémáját nehéz megoldani, még akkor is, ha a saját szerveréről beszélünk, akkor az 500 megabájtos fájlok mozgatása nem túl egyszerű, és még tárhelyen és VDS-en sem egyszerűen nem növelheti a memóriát.

A PHP számos beépített XML feldolgozási opcióval rendelkezik - SimpleXML, DOM, SAX.
Mindezeket a lehetőségeket számos példacikk részletezi, de mindegyik példa bemutatja, hogyan kell dolgozni egy teljes XML-dokumentummal.

Íme egy példa, egy XML-fájlból kapunk egy objektumot

Most már feldolgozhatja ezt az objektumot, DE...
Amint látja, a teljes XML-fájlt a rendszer beolvassa a memóriába, majd mindent egy objektummá értelmez.
Vagyis minden adat a memóriába kerül, és ha a lefoglalt memória nem elegendő, akkor a szkript leáll.

Ez az opció nem alkalmas nagy fájlok feldolgozására, soronként kell olvasni a fájlt, és sorra kell feldolgozni ezeket az adatokat.
Ugyanakkor az adatok feldolgozása során az érvényesség ellenőrzése is megtörténik, így vissza kell tudni görgetni, például érvénytelen XML fájl esetén törölni kell az összes bevitt adatbázist, vagy két átmegy a fájlon, először beolvassa az érvényességet, majd olvassa el az adatok feldolgozásához.

Itt van egy elméleti példa egy nagy XML-fájl elemzésére.
Ez a szkript beolvas egy karaktert egy fájlból, ezeket az adatokat blokkokba gyűjti és elküldi az XML elemzőnek.
Ez a megközelítés teljesen megoldja a memóriaproblémát, és nem okoz terhelést, de idővel súlyosbítja a problémát. Az alábbiakban olvashat arról, hogyan próbálja meg megoldani a problémát idővel.

webi_xml($file) függvény
{

########
### adatkezelési funkció

{
nyomtatás $adatok ;
}
############################################



{
nyomtatás $név ;
print_r($attrs);
}


## záró tag funkció
függvény endElement ($elemző , $név )
{
nyomtatás $név ;
}
############################################

($xml_parser , "adatok" );

// fájl megnyitása
$fp = fopen($file , "r" );

$perviy_vxod = 1 ; $adat = "" ;



{

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


if($simvol != ">" ) ( folytatás;)


visszhang"

szünet;
}

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

webi_xml("1.xml");

?>

Ebben a példában mindent egy webi_xml () függvénybe raktam, és a hívása a legalul látható.
Maga a szkript három fő funkcióból áll:
1. Egy függvény, amely elkapja a startElement() címke nyitását
2. Egy függvény, amely elkapja az endElement() címke bezárását
3. És az adatokat fogadó függvény data() .

Tegyük fel, hogy az 1.xml fájl tartalma egy recept



< title >egyszerű kenyér
< ingredient amount = "3" unit = "стакан" >Liszt
< ingredient amount = "0.25" unit = "грамм" >Élesztő
< ingredient amount = "1.5" unit = "стакан" >meleg víz
< ingredient amount = "1" unit = "чайная ложка" >Só
< instructions >
< step > Az összes hozzávalót összekeverjük és alaposan összegyúrjuk.
< step > Fedjük le egy ruhával, és hagyjuk egy órán át meleg szobában.
< step > Ismét összegyúrjuk, tepsire tesszük és betesszük a sütőbe.
< step > Látogassa meg a webhely webhelyét


Kezdjük a webi_xml("1.xml") általános függvény meghívásával;
Ebben a funkcióban az elemző elindul, és az összes címkenév le lesz fordítva nagybetűs hogy minden címkének ugyanaz a kis- és nagybetűje legyen.

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

Most megadjuk, hogy mely funkciók fognak működni a címke megnyitásának, bezárásának és adatfeldolgozásának elfogására

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

Következik a megadott fájl megnyitása, ismétlés a fájlon egy karakterrel, és minden karakter hozzáadódik a karakterlánc változóhoz, amíg meg nem találja a karaktert > .
Ha ez az első hozzáférés a fájlhoz, akkor minden, ami a fájl elején felesleges, törlődik az út során, minden, ami előtte áll. , ezzel a címkével kell kezdődnie az XML-nek.
Az első alkalommal, amikor egy karakterlánc-változó gyűjt egy karakterláncot

És küldje el az elemzőnek
xml_parse ($xml_parser , $data , feof ($fp ));
Az adatok feldolgozása után a karakterlánc-változó alaphelyzetbe áll, és újra kezdődik az adatok karakterláncba gyűjtése, és másodszor jön létre egy karakterlánc

A harmadikban
</b><br>a negyedikben <br><b>egyszerű kenyér

Kérjük, vegye figyelembe, hogy a karakterlánc-változót mindig a befejezett címke alkotja > és nem szükséges például nyitott és zárt címkéket adatokkal elküldeni a dekomposernek
egyszerű kenyér
Ennek a kezelőnek fontos, hogy egy egész bontatlan címkét kapjon, legalább egy nyitott címkét, és a következő lépésben egy zárt címkét, vagy azonnal kapjon 1000 sort a fájlból, mindegy, a lényeg, hogy a címke nem törik például

le>Egyszerű kenyér
Így nem lehet adatot küldeni a kezelőnek, mert a címke elromlott.
Ki lehet találni egy saját módszert a kezelőnek való adatküldésre, például gyűjts össze 1 megabájt adatot és küldd el a kezelőnek a sebesség növelése érdekében, csak ügyelj arra, hogy a címkék mindig véget érjenek, és az adatok törhetők
Egyszerű</b><br><b>kenyér

Így, részletekben, tetszés szerint küldheti nagy fájl a felvezetőnek.

Most nézzük meg, hogyan dolgozzák fel ezeket az adatokat, és hogyan szerezhetők be.

Kezdve a nyitó címkék funkcióval startElement ($parser , $name , $attrs )
Tegyük fel, hogy a feldolgozás elérte a sort
< ingredient amount = "3" unit = "стакан" >Liszt
Ekkor a függvényen belül a $name változó egyenlő lesz hozzávaló vagyis a nyitott címke neve (az ügy még nem érte el a címke lezárását).
Benne is ez az eset a $attrs címke attribútumainak tömbje elérhető lesz, amelyben lesznek adatok mennyiség = "3" és egység = "üveg".

Ezt követően a nyitott címke adatait feldolgozta a függvény adatok ($parser , $data )
A $data változó mindent tartalmaz, ami a nyitó és záró címke között van, esetünkben ez a Muk szöveg

És a karakterláncunk függvény általi feldolgozása befejeződött endElement ($elemző , $név )
Ez a zárt címke neve, esetünkben a $name egyenlő lesz hozzávaló

Utána pedig ismét körbejárt az egész.

A fenti példa csak az XML feldolgozás elvét mutatja be, de a valós alkalmazáshoz azt véglegesíteni kell.
Általában nagy XML-t kell elemezni ahhoz, hogy adatokat vigyünk be az adatbázisba, és a megfelelő adatfeldolgozáshoz tudnia kell, hogy az adatok melyik nyitott címkéhez tartoznak, milyen szintű címkebeágyazás, és mely címkék vannak nyitva a fenti hierarchiában. Ezen információk birtokában probléma nélkül tudja megfelelően feldolgozni a fájlt.
Ehhez több globális változót kell bevezetnie, amelyek információkat gyűjtenek a nyitott címkékről, a beágyazásról és az adatokról.
Íme egy használható példa

webi_xml($file) függvény
{
globális $webi_depth ; // számláló a fészkelési mélység nyomon követéséhez
$webi_mélység = 0 ;
globális $webi_tag_open ; // tartalmazni fog egy tömböt az open in Ebben a pillanatban címkéket
$webi_tag_open = array();
globális $webi_data_temp ; // ez a tömb egy címke adatait fogja tartalmazni

####################################################
### adatkezelési funkció
függvényadatok ($parser , $data )
{
globális $webi_depth ;
globális $webi_tag_open ;
globális $webi_data_temp ;
// adatok hozzáadása a tömbhöz egymásba ágyazással és jelenleg megnyitott címkével
$webi_data_temp [ $webi_depth ][ $webi_tag_open [ $webi_depth ]][ "data" ].= $adat ;
}
############################################

####################################################
### nyitó címke funkció
függvény startElement ($parser , $name , $attrs )
{
globális $webi_depth ;
globális $webi_tag_open ;
globális $webi_data_temp ;

// ha a beágyazási szint még nem nulla, akkor egy címke már nyitva van
// és az abból származó adatok már a tömbben vannak, akkor ezeket feldolgozhatja
ha ($webi_depth)
{




" ;

nyomtatás"
" ;
print_r($webi_tag_open); // nyitott címkék tömbje
nyomtatás"


" ;

// az adatok feldolgozása után törölje azokat a memória felszabadítása érdekében
unset($GLOBALS [ "webi_data_temp" ][ $webi_depth ]);
}

// most megkezdődött a következő címke megnyitása, és a további feldolgozás a következő lépésben történik
$webi_depth++; // fészkelődés növelése

$webi_tag_open [ $webi_depth ]= $név ; // nyitott címke hozzáadása az információs tömbhöz
$webi_data_temp [ $webi_depth ][ $name ][ "attrs" ]= $attrs ; // most adjunk hozzá címkeattribútumokat

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

#################################################
## záró tag funkció
függvény endElement ($elemző , $név ) (
globális $webi_depth ;
globális $webi_tag_open ;
globális $webi_data_temp ;

// itt kezdődik az adatfeldolgozás, például az adatbázisba való felvétel, fájlba mentés stb.
// A $webi_tag_open nyitott címkék láncát tartalmazza beágyazási szint szerint
// például a $webi_tag_open[$webi_depth] tartalmazza annak a nyitott tagnek a nevét, amelynek információi jelenleg feldolgozás alatt állnak
// $webi_depth címke beágyazási szintje
// $webi_data_temp[$webi_depth][$webi_tag_open[$webi_depth]]["attrs"] címkeattribútumok tömbje
// $webi_data_temp[$webi_depth][$webi_tag_open[$webi_depth]]["data"] címkeadatok

Nyomtassa ki az "adatokat". $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" ]);
nyomtatás"
" ;
print_r($webi_tag_open);
nyomtatás"


" ;

Unset($GLOBALS [ "webi_data_temp" ]); // az adatok feldolgozása után töröljük a tömböt az adatok egészével, mivel a címke zárva volt
unset($GLOBALS [ "webi_tag_open" ][ $webi_depth ]); // információ eltávolítása erről a megnyitott címkéről... mivel bezárta

$webi_depth --; // csökkenti a beágyazást
}
############################################

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

// adja meg, hogy mely funkciók működjenek a címkék megnyitásakor és bezárásakor
xml_set_element_handler($xml_parser , "startElement" , "endElement" );

// függvény megadása az adatokkal való munkavégzéshez
xml_set_character_data_handler($xml_parser , "adatok" );

// fájl megnyitása
$fp = fopen($file , "r" );

$perviy_vxod = 1 ; // jelző a fájl első bemenetének ellenőrzéséhez
$adat = "" ; // itt összegyűjtjük a fájlból az adatok egy részét, és elküldjük az xml elemzőnek

// ciklus a fájl végéig
míg (! feof ($fp ) és $fp )
{
$simvol = fgetc($fp); // beolvas egy karaktert a fájlból
$adat .= $simvol ; // adjuk hozzá ezt a karaktert a küldendő adatokhoz

// ha a karakter nem a végcímke, akkor térjen vissza a ciklus elejére, és adjon hozzá még egy karaktert az adatokhoz, és így tovább, amíg meg nem találja a végcímkét
if($simvol != ">" ) ( folytatás;)
// ha a záró címkét megtalálták, most küldje el ezeket az összegyűjtött adatokat feldolgozásra

// ellenőrizze, hogy ez az első bejegyzés a fájlban, majd töröljön mindent, ami a címke előtt van// mivel néha előfordulhat, hogy az XML kezdete előtt szemét található (ügyetlen szerkesztők, vagy a fájlt egy másik szerverről kapta a szkript)
if($perviy_vxod ) ( $data = strstr ($data , "

// most adatokat dobunk az xml elemzőbe
if (! xml_parse ($xml_parser , $data , feof ($fp ))) (

// itt lehet feldolgozni és érvényességi hibákat kérni...
// amint hiba történik, az elemzés leáll
visszhang"
XML-hiba: " .xml_error_string (xml_get_error_code ($xml_parser ));
visszhang "vonalnál" . xml_get_current_line_number($xml_parser );
szünet;
}

// elemzés után az összegyűjtött adatokat kidobjuk a ciklus következő lépéséhez.
$adat = "" ;
}
fclose($fp);
xml_parser_free($xml_parser );
// globális változók törlése
unset($GLOBALS [ "webi_depth" ]);
unset($GLOBALS [ "webi_tag_open" ]);
unset($GLOBALS [ "webi_data_temp" ]);

webi_xml("1.xml");

?>

Az egész példát megjegyzések kísérték, most teszteljetek és kísérletezzetek.
Kérjük, vegye figyelembe, hogy az adatkezelési funkcióban az adatok nem egyszerűen bekerülnek a tömbbe, hanem a " .=" mivel az adatok nem biztos, hogy teljes formában érkeznek, és ha csak egy feladatot adsz meg, akkor időről időre darabokban kapod meg az adatokat.

Nos, ennyi, most tetszőleges méretű fájl feldolgozásakor lesz elegendő memória, de a szkript futási ideje többféleképpen növelhető.
Szúrjon be egy függvényt a szkript elejére
set_time_limit(6000);
vagy
ini_set("max_végrehajtási_idő" , "6000" );

Vagy adjon hozzá szöveget a .htaccess fájlhoz
php_value max_execution_time 6000

Ezek a példák a szkript futási idejét 6000 másodpercre növelik.
Az időt ilyen módon csak kikapcsolt csökkentett módban növelheti.

Ha van hozzáférése a php.ini szerkesztéséhez, növelheti az időt a következővel
maximális_végrehajtási_idő = 6000

Például a masterhost tárhelyen az írás idején a szkriptidő növelése tilos, annak ellenére biztonságos mód, de ha profi vagy, építhetsz php-t a masterhost-ra, de ez nem szerepel ebben a cikkben.

Most az XML-lel való munkát fogjuk tanulmányozni. Az XML a webhelyek közötti adatcsere formátuma. Nagyon hasonlít a HTML-hez, csak az XML engedélyezi a saját címkéit és attribútumait.

Miért van szükség XML-re az elemzéshez? Néha előfordul, hogy az elemezni kívánt webhelynek van egy API-ja, amely lehetővé teszi, hogy különösebb erőfeszítés nélkül megkapja, amit akar. Ezért azonnal tanácsot adjon – a webhely elemzése előtt ellenőrizze, hogy van-e API-ja.

Mi az API? Ez egy olyan funkciókészlet, amellyel kérést küldhet erre az oldalra, és megkaphatja a kívánt választ. Ez a válasz leggyakrabban XML formátumban érkezik. Tehát kezdjük el tanulmányozni.

XML-lel végzett munka PHP-ben

Tegyük fel, hogy van XML-je. Lehet karakterláncban, fájlban tárolva, vagy kérésre kiszolgálható egy adott URL-re.

Legyen az XML egy karakterláncban tárolva. Ebben az esetben ebből a sorból kell létrehoznia egy objektumot a segítségével új SimpleXMLElement:

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

Most van egy változónk $xml elemzett XML-lel rendelkező objektum kerül tárolásra. Az objektum tulajdonságainak elérésével hozzáférhet az XML-címkék tartalmához. Hogyan pontosan - egy kicsit lejjebb elemezzük.

Ha az XML fájlban van tárolva, vagy egy URL elérésével tér vissza (ami leggyakrabban így van), akkor használja a függvényt simplexml_load_file amely ugyanazt a tárgyat teszi $xml:

Kolya 25 1000

$xml = simplexml_load_file(fájl elérési útja vagy url);

Munkamódszerek

Az alábbi példákban az XML-t fájlban vagy URL-ben tároljuk.

Legyen megadva a következő XML:

Kolya 25 1000

Nézzük meg egy alkalmazott nevét, életkorát és fizetését:

$xml = simplexml_load_file(fájl elérési útja vagy url); echo $xml->név; //megjeleníti a "Kolya" echo $xml->age; //kimenetek 25 echo $xml->fizetés; //1000-et ad ki

Amint látható, a $xml objektum a címkéknek megfelelő tulajdonságokkal rendelkezik.

Talán észrevetted, hogy a címke sehol nem jelenik meg a forgalomban. Ez azért van, mert ez a gyökércímke. Átnevezheti például a következőre - és semmi sem fog változni:

Kolya 25 1000

$xml = simplexml_load_file(fájl elérési útja vagy url); echo $xml->név; //megjeleníti a "Kolya" echo $xml->age; //kimenetek 25 echo $xml->fizetés; //1000-et ad ki

Az XML-ben csak egy gyökércímke lehet, akárcsak a gyökércímke sima HTML-ben.

Módosítsuk egy kicsit az XML-ünket:

Kolya 25 1000

Ebben az esetben egy hívásláncot kapunk:

$xml = simplexml_load_file(fájl elérési útja vagy url); echo $xml->dolgozó->név; //megjeleníti "Kolya" echo $xml->worker->age; //25-öt ad ki echo $xml->dolgozó->bér; //1000-et ad ki

Munka az attribútumokkal

Néhány adatot tároljunk attribútumokban:

1. szám

$xml = simplexml_load_file(fájl elérési útja vagy url); echo $xml->dolgozó["név"]; //megjeleníti "Kolya" echo $xml->worker["age"]; //kimenet 25 echo $xml->dolgozó["fizetés"]; //kimenetek 1000 echo $xml->worker; //kiírja az "1-es számot"

Címkék kötőjelekkel

Az XML-ben a kötőjellel ellátott címkék (és attribútumok) megengedettek. Ebben az esetben az ilyen címkék a következőképpen érhetők el:

Kolya Ivanov

$xml = simplexml_load_file(fájl elérési útja vagy url); echo $xml->dolgozó->(keresztnév); //megjeleníti "Kolya" echo $xml->worker->(last-name); //megjeleníti az "Ivanov" kifejezést

Hurok iteráció

Most ne egy munkásunk legyen, hanem több. Ebben az esetben egy foreach ciklussal iterálhatjuk az objektumunkat:

Kolya 25 1000 Vasya 26 2000 Péter 27 3000

$xml = simplexml_load_file(fájl elérési útja vagy url); foreach ($xml mint $worker) ( echo $worker->name; //kiírja: "Kolya", "Vasya", "Petya" )

Objektumtól normál tömbig

Ha nem érzi jól magát egy objektummal dolgozni, a következő trükkel átalakíthatja azt normál PHP tömbbé:

$xml = simplexml_load_file(fájl elérési útja vagy url); var_dump(json_decode(json_encode($xml), true));

Több információ

Elemzés a sitemap.xml alapján

Egy webhely gyakran tartalmaz egy sitemap.xml fájlt. Ez a fájl a webhely összes oldalára mutató hivatkozásokat tárol a keresőmotorok általi indexelés megkönnyítése érdekében (az indexelés valójában a webhely Yandex és Google általi elemzése).

Általában nem nagyon kell törődnünk azzal, hogy miért van szükség erre a fájlra, a lényeg az, hogy ha létezik, akkor ne mászhasson fel az oldal oldalain semmilyen trükkös módszerrel, hanem egyszerűen használja ezt a fájlt.

A fájl meglétének ellenőrzése: elemezzük a site.ru webhelyet, majd keresse fel a site.ru/sitemap.xml fájlt a böngészőben - ha lát valamit, akkor ott van, és ha nem látja, akkor sajnos.

Ha van webhelytérkép, akkor az XML formátumban tartalmazza a webhely összes oldalára mutató hivatkozásokat. Nyugodtan vegye ezt az XML-t, elemezze, különítse el a szükséges oldalakra mutató hivatkozásokat az Ön számára megfelelő módon (például a pók módszernél leírt URL elemzésével).

Ennek eredményeként megkapja az elemzéshez szükséges linkek listáját, és csak rá kell mennie, és elemeznie kell a szükséges tartalmat.

További információ a sitemap.xml eszközről a wikipédiában.

Mit csinálsz ezután:

Kezdje el a problémák megoldását az alábbi linken: feladatok az órán.

Ha minden eldőlt, folytassa egy új téma tanulmányozásával.

Ha hibát észlel, jelöljön ki egy szövegrészt, és nyomja meg a Ctrl + Enter billentyűket
OSSZA MEG: