xml sənədinin təhlili. XML məlumatlarının təhlili. Ayrışdırıcının Nümunəsinin Yaradılması

XML-in təhlili əslində XML sənədindən keçmək və müvafiq məlumatları qaytarmaq deməkdir. Getdikcə artan veb xidmətləri JSON formatında məlumatları qaytarsa ​​da, əksəriyyəti hələ də XML-dən istifadə edir, ona görə də mövcud API-lərin tam spektrindən istifadə etmək istəyirsinizsə, XML təhlilini mənimsəmək vacibdir.

Uzatmanın istifadəsi SimpleXML PHP 5.0-də yenidən əlavə edilmiş PHP-də XML ilə işləmək çox asan və sadədir. Bu yazıda bunu necə edəcəyinizi sizə göstərəcəyəm.

İstifadə Əsasları

Aşağıdakı nümunə ilə başlayaq dillər.xml:


>

> 1972>
> Dennis Ritchie >
>

> 1995>
> Rasmus Lerdorf >
>

> 1995>
> James Gosling >
>
>

Bu XML sənədində hər bir dil haqqında bəzi məlumatlar olan proqramlaşdırma dillərinin siyahısı var: onun həyata keçirildiyi il və yaradıcısının adı.

İlk addım funksiyalardan istifadə edərək XML-i yükləməkdir simplexml_load_file(), və ya simplexml_load_string(). Funksiyaların adından göründüyü kimi, birincisi fayldan XML-i, ikincisi isə sətirdən XML-i yükləyəcək.

Hər iki funksiya bütün DOM ağacını yaddaşa oxuyur və obyekti qaytarır SimpleXMLElement. Yuxarıdakı nümunədə obyekt $languages ​​dəyişənində saxlanılır. Funksiyalardan istifadə edə bilərsiniz var_dump() və ya çap_r() istəsəniz qaytarılan obyekt haqqında ətraflı məlumat əldə etmək.

SimpleXMLElement Obyekt
[lang] => Massiv
[ 0 ] => SimpleXMLElementObject
[@atributlar] => Massiv
[ad] => C
[peyda oldu] => 1972
[yaradıcı] => Dennis Ritchie
[ 1 ] => SimpleXMLElement Obyekt
[@atributlar] => Massiv
[ad] => PHP
[peyda oldu] => 1995
[yaradıcı] => Rasmus Lerdorf
[ 2 ] => SimpleXMLElement Obyekt
[@atributlar] => Massiv
[ad] => Java
[peyda oldu] => 1995
[yaradıcı] => James Gosling
)
)

Bu XML kök elementi ehtiva edir dillər, üç elementdən ibarətdir dil. Hər bir massiv elementi bir elementə uyğundur dil XML sənədində.

Operatordan istifadə edərək obyektin xassələrinə daxil ola bilərsiniz -> . Məsələn, $languages->lang sizə birinci elementə uyğun gələn SimpleXMLElement obyektini qaytaracaq dil. Bu obyekt iki xassədən ibarətdir: ortaya çıxdı və yaradıcı.

$languages ​​-> lang [ 0 ] -> göründü;
$languages ​​-> lang [ 0 ] -> yaradıcı ;

kimi standart bir döngə ilə dillərin siyahısını göstərmək və onların xassələrini göstərmək çox asandır foreach.

foreach ($languages ​​-> lang $lang kimi) (
çapf(
"" ,
$lang["ad"] ,
$lang -> göründü,
$lang -> yaradıcı
) ;
}

Dilin adını almaq üçün lang elementinin atribut adına necə daxil olduğuma diqqət yetirin. Bu yolla siz SimpleXMLElement obyekti kimi təqdim olunan elementin istənilən atributuna daxil ola bilərsiniz.

Ad boşluqları ilə işləmək

Müxtəlif veb xidmətlərinin XML ilə işləyərkən siz tez-tez element ad boşluqları ilə qarşılaşacaqsınız. Özümüzü dəyişək dillər.xml ad boşluğundan istifadə nümunəsini göstərmək üçün:



xmlns:dc =>

> 1972>
> Dennis Ritchie >
>

> 1995>
> Rasmus Lerdorf >
>

> 1995>
> James Gosling >
>
>

İndi element yaradan ad sahəsinə yerləşdirilir DC, bu http://purl.org/dc/elements/1.1/ ünvanına işarə edir. Əvvəlki kodumuzdan istifadə edərək dil yaradıcılarını çap etməyə çalışsanız, bu işləməyəcək. Element ad boşluqlarını oxumaq üçün aşağıdakı yanaşmalardan birini istifadə etməlisiniz.

Birinci yanaşma elementin ad sahəsinə istinad edərkən URI adlarını birbaşa kodda istifadə etməkdir. Aşağıdakı nümunə bunun necə edildiyini göstərir:

$dc = $dillər -> lang [ 1 ] -> uşaqlar( "http://purl.org/dc/elements/1.1/") ;
echo $dc -> yaradıcı ;

Metod uşaqlar() ad sahəsi götürür və prefikslə başlayan uşaq elementləri qaytarır. Bu, iki arqument tələb edir, birincisi XML ad sahəsidir, ikincisi isə defolt olaraq isteğe bağlı arqumentdir. yalan. İkinci arqument TRUE olaraq təyin edilərsə, ad sahəsi prefiks kimi qəbul ediləcək. FALSE olarsa, ad sahəsi URL ad sahəsi kimi qəbul ediləcək.

İkinci yanaşma sənəddən URI adlarını oxumaq və elementin ad sahəsinə istinad edərkən onlardan istifadə etməkdir. Bu, əslində elementlərə daxil olmağın ən yaxşı yoludur, çünki URI-yə sərt kodlaşdırılmağa ehtiyac yoxdur.

$namespaces = $dillər -> getNamespaces (true) ;
$dc = $dillər -> lang [ 1 ] -> uşaqlar ($namespaces [ "dc" ] );

echo $dc -> yaradıcı ;

Metod GetNamespaces() prefiks adlarının və onlarla əlaqəli URI-lərin bir sırasını qaytarır. Defolt olan əlavə parametr tələb edir yalan. kimi quraşdırsanız doğru, onda bu üsul ana və uşaq qovşaqlarında istifadə olunan adları qaytaracaq. Əks halda, o, yalnız ana qovşaqda istifadə olunan ad boşluqlarını tapır.

İndi bu kimi dillər siyahısında təkrarlaya bilərsiniz:

$dillər = simplexml_load_file ("languages.xml" );
$ns = $dillər -> getNamespaces (true) ;

foreach ($languages ​​-> lang $lang kimi) (
$dc = $lang -> uşaqlar ($ns [ "dc" ] );
çapf(
"

%s %d içində göründü və %s tərəfindən yaradıldı.

" ,
$lang["ad"] ,
$lang -> göründü,
$dc -> yaradıcı
) ;
}

Case Study - YouTube Video Kanalının təhlili

Gəlin RSS lentini qəbul edən bir nümunəyə baxaq YouTube kanalı və ondan bütün videolara keçidləri göstərir. Bunun üçün aşağıdakı ünvanla əlaqə saxlamağınız xahiş olunur:

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

URL verilmiş kanaldan XML formatında ən son videoların siyahısını qaytarır. XML-i təhlil edəcəyik və hər bir video üçün aşağıdakı məlumatları alacağıq:

  • Videoya keçid
  • Miniatür
  • ad

XML-in axtarışı və yüklənməsi ilə başlayacağıq:

$channel = "KanalAdı" ;
$url = "http://gdata.youtube.com/feeds/api/users/". $kanal. "/yükləmələr" ;
$xml = file_get_contents ($url );

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

XML lentinə baxsanız, orada bir neçə elementin olduğunu görə bilərsiniz. qurum, hər biri mağazalar ətraflı məlumat kanaldan xüsusi bir video haqqında. Lakin biz yalnız şəkil miniatürlərindən, video ünvanından və başlıqdan istifadə edirik. Bu üç element elementin uşaqlarıdır qrup, bu da öz növbəsində övladıdır giriş:

>

>



Başlıq... >

>

>

Yalnız bütün elementləri nəzərdən keçirəcəyik giriş, və onların hər biri üçün lazımi məlumatları çıxarın. qeyd edin ki oyunçu, miniatürbaşlıq media ad məkanındadır. Beləliklə, əvvəlki nümunədə olduğu kimi davam etməliyik. Biz adları sənəddən alırıq və elementlərə istinad edərkən ad boşluğundan istifadə edirik.

foreach ($feed -> $entry kimi giriş) (
$group = $entry -> uşaqlar ($ns [ "media" ] );
$qrup = $qrup -> qrup;
$thumbnail_attrs = $qrup -> miniatür [ 1 ] -> atributlar () ;
$image = $thumbnail_attrs [ "url" ] ;
$player = $qrup -> oyunçu -> atributlar () ;
$link = $player["url"] ;
$title = $qrup -> başlıq;
çapf( "

" ,
$player , $image , $title );
}

Nəticə

İndi necə istifadə edəcəyinizi bilirsiniz SimpleXML XML məlumatlarını təhlil etmək üçün müxtəlif API-lərlə müxtəlif XML lentlərini təhlil edərək bacarıqlarınızı təkmilləşdirə bilərsiniz. Lakin nəzərə almaq vacibdir ki, SimpleXML bütün DOM-u yaddaşa oxuyur, ona görə də böyük verilənlər toplusunu təhlil edirsinizsə, yaddaşınız tükənə bilər. SimpleXML haqqında daha çox öyrənmək üçün sənədləri oxuyun.


Hər hansı bir sualınız varsa, lütfən bizimlə əlaqə saxlayın

Genişlənən İşarələmə Dili XML sənədlərin maşın tərəfindən oxuna bilən formada kodlaşdırılması üçün qaydalar toplusudur. XML İnternetdə məlumat mübadiləsi üçün məşhur formatdır. Xəbər saytları və ya bloqlar kimi məzmununu tez-tez yeniləyən saytlar, xarici proqramların məzmun dəyişikliklərindən xəbərdar olması üçün tez-tez XML lenti təqdim edirlər. XML məlumatlarının göndərilməsi və təhlili şəbəkə bağlantısı olan proqramlar üçün ümumi işdir. Bu dərs XML sənədlərini necə təhlil etməyi və onların məlumatlarından istifadə etməyi izah edir.

Ayrışdırıcının seçilməsi

Kanal təhlili

Lenti təhlil etməyin ilk addımı hansı məlumat sahələri ilə maraqlandığınıza qərar verməkdir. Parser verilmiş sahələri çıxarır və qalan hər şeyə məhəl qoymur.

Budur, nümunə tətbiqdə təhlil ediləcək kanal parçası. StackOverflow.com-dakı hər bir yazı lentdə bir neçə iç-içə teq olan giriş teqi kimi görünür:

android etiketli ən yeni suallar - Stack Overflow ... ... http://stackoverflow.com/q/9439999 0 Məlumat faylım haradadır? uçurum 2310 http://stackoverflow.com/users/1128925 2012-02-25T00:30:54Z 2012-02-25T00:30:54Z

Məlumat faylı tələb edən bir tətbiqim var...

... ...

Nümunə proqram giriş teqindən və onun alt etiketlərindən başlıq, keçid və xülasədən məlumatları alır.

Ayrışdırıcının Nümunəsinin Yaradılması

Növbəti addım analizatoru işə salmaq və təhlil prosesinə başlamaqdır. Bu fraqmentdə analizator ad boşluqlarını idarə etməmək və həmçinin təqdim edilmiş InputStream-dən giriş kimi istifadə etmək üçün işə salınıb. Təhlil prosesi nextTag()-a zənglə başlayır və proqramın maraqlandığı məlumatları əldə edən və emal edən readFeed() metodunu çağırır:

İctimai sinif StackOverflowXmlParser ( // Biz ad boşluqlarından istifadə etmirik şəxsi statik final String ns = null; ictimai Siyahı təhlili (InputStream in) XmlPullParserException, IOException atır ( cəhd edin ( XmlPullParser parser = Xml.newPullParserFe(); parser.NEWPullParserFe(); parser. BOŞLAR , false); parser.setInput(in, null); parser.nextTag(); readFeed(parser); ) qaytarın (in.close(); ) ) ... )

kanalı çıxarın

readFeed() metodu feedin emalı üzrə faktiki işi görür. "Giriş" etiketi ilə qeyd olunan elementlər rekursiv kanalın işlənməsi üçün başlanğıc nöqtəsidir. Növbəti teq giriş teqi deyilsə, atlanır. Bütün "lent" rekursiv şəkildə işləndikdən sonra, readFeed() lentdən çıxarılan girişləri (o cümlədən, iç-içə daxil edilmiş məlumat elementləri) ehtiva edən Siyahı qaytarır. Bu Siyahı sonra təhlilçi tərəfindən qaytarılır.

Şəxsi Siyahı readFeed(XmlPullParser parser) XmlPullParserException, IOException atır (Siyahı qeydləri = yeni ArrayList (); parser.require(XmlPullParser.START_TAG, ns, "feed"); while (parser.next() != XmlPull if (XmlPull)arser.ENDTAGP (parser.getEventType() != XmlPullParser.START_TAG) ( davam; ) Sətir adı = parser.getName(); // Əgər (name.equals("entry")) ( entries.add() giriş teqini axtararaq başlayır. readEntry(parser)); ) else ( skip(parser); ) ) girişləri qaytarın; )

XML təhlili

XML lentini təhlil etmək üçün addımlar aşağıdakılardır:

Bu parça, təhlilçinin giriş, başlıq, keçid və xülasəni necə təhlil etdiyini göstərir.

İctimai statik sinif Giriş ( ictimai yekun Sətir başlığı; açıq yekun Sətir linki; ictimai yekun Sətir xülasəsi; özəl Entry (String başlığı, Simli xülasə, Simli keçid) ( this.title = başlıq; this.summary = xülasə; this.link = link ; ) ) // Girişin məzmununu təhlil edir. Başlıq, xülasə və ya keçid etiketi ilə qarşılaşarsa, onları emal üçün // müvafiq "oxumaq" metodlarına təhvil verir. Əks halda, etiketi atlayın. Şəxsi Giriş readEntry(XmlPullParser parser) XmlPullParserException, IOException atır ( parser.require(XmlPullParser.START_TAG, ns, "entry"); Sətir başlığı = null; Sətir xülasəsi = null; Sətir keçidi = null; while (parser.next() ! = XmlPullParser.END_TAG) ( əgər (parser.getEventType() != XmlPullParser.START_TAG) (davam etmək; ) Sətir adı = parser.getName(); if (name.equals("title")) ( başlıq = readTitle(parser) ; ) else if (name.equals("summary")) ( xülasə = readSummary(parser); ) else if (name.equals("link")) ( link = readLink(parser); ) else ( skip(parser) ; ) ) yeni Entry qaytarın(başlıq, xülasə, keçid); ) // Lentdə başlıq teqlərini emal edir. özəl String readTitle(XmlPullParser parser) IOException, XmlPullParserException atır ( parser.require(XmlPullParser.START_TAG, ns, "title"); String title = readText(parser); parser.require(XmlPullParser.END_TAG,"ns); başlığı qaytarın; ) // Lentdə keçid teqlərini emal edir. özəl String readLink(XmlPullParser parser) IOException, XmlPullParserException atır (String link = ""; parser.require(XmlPullParser.START_TAG, ns, "link"); String tag = parser.getName(); String relType = parser.getAnu(ValueAll) , "rel"); əgər (tag.equals("link")) ( if (relType.equals("alternate"))( link = parser.getAttributeValue(null, "href"); parser.nextTag(); ) ) parser.require(XmlPullParser.END_TAG, ns, "link"); qaytarma linki; ) // Lentdə xülasə teqlərini emal edir. özəl String readSummary(XmlPullParser parser) IOException, XmlPullParserException atır ( parser.require(XmlPullParser.START_TAG, ns, "summary"); Sətir xülasəsi = readText(parser); parser.require(XmlPullParserns.END_TAG,"summa); xülasə qaytarın; ) // Teqlərin başlığı və xülasəsi üçün onların mətn dəyərlərini çıxarır. özəl String readText(XmlPullParser parser) IOException, XmlPullParserException atır ( String result = ""; if (parser.next() == XmlPullParser.TEXT) ( result = parser.getText(); parser.nextTag(); ) nəticəsini qaytarın; ) ... )

Ehtiyacınız olmayan elementləri atlayın

Yuxarıda təsvir edilən XML təhlili addımlarından birində təhlilçi bizi maraqlandırmayan teqləri ötür. Aşağıda skip() metodu üçün parser kodu verilmişdir:

Private void skip(XmlPullParser parser) XmlPullParserException, IOException (if (parser.getEventType() != XmlPullParser.START_TAG) atır (yeni IllegalStateException(); ) int dərinliyi = 1; while (dərinlik (!ser) keçidi (!parser) sonrakı()) ( XmlPullParser.END_TAG: dərinlik--; fasilə; XmlPullParser.START_TAG: dərinlik++; fasilə; ) ) )

Bu necə işləyir:

  • Cari hadisə START_TAG deyilsə, metod istisna yaradır.
  • O, START_TAG və END_TAG-a qədər olan bütün tədbirləri istehlak edir.
  • Orijinal START_TAG-dan sonra rastlaşdığı ilk teqdə deyil, düzgün END_TAG nöqtəsində dayandığından əmin olmaq üçün o, yuvalama dərinliyini izləyir.

Beləliklə, əgər cari elementdə yuvalanmış elementlər varsa, təhlilçi orijinal START_TAG və onun uyğun END_TAG arasındakı bütün hadisələri emal edənə qədər dərinlik 0 olmayacaq. Məsələn, təhlilçinin necə atladığını düşünün 2 yuvalanmış elementi olan element, :

  • while döngəsindən ilk keçdikdə, təhlilçinin ondan sonra qarşılaşdığı növbəti tag bu START_TAG üçün
  • while dövrəsindən ikinci keçiddə təhlilçinin qarşılaşdığı növbəti teq END_TAG olur
  • while dövrəsindən üçüncü keçiddə təhlilçinin qarşılaşdığı növbəti teq START_TAG-dır . Dərinlik dəyəri 2-ə qədər artır.
  • while dövrəsindən dördüncü keçiddə təhlilçinin qarşılaşdığı növbəti teq END_TAG olur. Dərinlik dəyəri 1-ə endirilir.
  • while dövrəsindən beşinci və sonuncu keçiddə təhlilçinin qarşılaşdığı növbəti teq END_TAG olur.. Dərinlik dəyəri 0-a qədər azalır ki, bunu göstərir element uğurla atlandı.

XML məlumatlarının emalı

Nümunə tətbiqi AsyncTask-da XML lentini qəbul edir və təhlil edir. Emal əsas UI ipindən kənarda həyata keçirilir. Emal tamamlandıqda, proqram əsas fəaliyyətdə (NetworkActivity) istifadəçi interfeysini yeniləyir.

Aşağıdakı fraqmentdə loadPage() metodu aşağıdakıları edir:

  • XML lentinə işarə edən URL dəyəri ilə sətir dəyişənini işə salır.
  • İstifadəçinin parametrləri və şəbəkə bağlantısı imkan verirsə, yeni DownloadXmlTask().execute(url) funksiyasını çağırır. Bu, yeni DownloadXmlTask ​​obyekti (AsyncTask alt sinfi) yaradır və lenti endirən və təhlil edən və istifadəçi interfeysində göstəriləcək sətir nəticəsini qaytaran execute() metodunu icra edir.
ictimai sinif Şəbəkə Fəaliyyəti Fəaliyyəti genişləndirir ( ictimai statik yekun String WIFI = "Wi-Fi"; ictimai statik yekun String HƏR = "Hər hansı"; şəxsi statik yekun String URL = "http://stackoverflow.com/feeds/tag?tagnames=android&sort =newest"; // Wi-Fi bağlantısı olub-olmaması. şəxsi statik boolean wifiConnected = false; // Mobil əlaqənin olub-olmaması. şəxsi statik boolean mobileConnected = false; // Ekranın yenilənməsinin olub-olmaması. ictimai statik boolean refreshDisplay = doğru; ictimai statik String sPref = null; ... // stackoverflow.com saytından XML lentini yükləmək üçün AsyncTask istifadə edir. public void loadPage() ( if((sPref. bərabərdir(HƏR)) && (wifiConnected || mobileConnected )) ( yeni DownloadXmlTask().execute(URL); ) else if ((sPref.equals(WIFI)) && (wifiConnected)) ( new DownloadXmlTask().execute(URL); ) else ( // xətanı göstər ) )
  • doInBackground() loadXmlFromNetwork() metodunu icra edir. Kanal URL-ni parametr kimi ötürür. loadXmlFromNetwork() metodu kanalı qəbul edir və emal edir. O, emalını başa vurduqda, yaranan sətri geri göndərir.
  • onPostExecute() qaytarılmış sətri götürür və onu istifadəçi interfeysində göstərir.
// stackoverflow.com saytından XML lentini endirmək üçün istifadə edilən AsyncTask-ın tətbiqi. Şəxsi sinif DownloadXmlTask ​​AsyncTask-ı genişləndirir ( @Override protected String doInBackground(String... urls) ( cəhd edin ( loadXmlFromNetwork(urls); ) tutmaq (IOException e) ( getResources().getString(R.string.connection_error); ) tutmaq (XmlPullParserException e) ( getResources().getString(R.string.xml_error); ) ) @Override protected void onPostExecute(String result) ( setContentView(R.layout.main); // WebView WebView myWebView vasitəsilə UI-də HTML sətirini göstərir = (WebView) findViewById(R.id.webview); myWebView.loadData(nəticə, "mətn/html", null); ) )

Aşağıda DownloadXmlTask-dan çağırılan loadXmlFromNetwork() metodu var. O, aşağıdakıları edir:

  1. StackOverflowXmlParser nümunəsini yaradır. O, həmçinin həmin sahələr üçün XML lentindən əldə edilmiş dəyərləri saxlamaq üçün Siyahı Girişi obyektləri və başlıq, url və xülasə üçün dəyişənlər yaradır.
  2. Lenti endirən və onu InputStream kimi qaytaran downloadUrl() çağırır.
  3. InputStream-i təhlil etmək üçün StackOverflowXmlParser istifadə edir. StackOverflowXmlParser Siyahı qeydlərini lentdən alınan məlumatlar ilə doldurur.
  4. Siyahı daxiletmələrini emal edir və lent məlumatlarını HTML işarələməsi ilə birləşdirir.
  5. Əsas fəaliyyətin istifadəçi interfeysində, onPostExecute() metodunda AsyncTask göstərilən HTML sətrini qaytarır.
// stackoverflow.com saytından XML yükləyir, təhlil edir və // HTML işarələməsi ilə birləşdirir. HTML sətirini qaytarır. şəxsi String loadXmlFromNetwork(String urlString) XmlPullParserException, IOException atır ( InputStream axını = null; // Analizləşdiricini işə salın StackOverflowXmlParser stackOverflowXmlParser = yeni StackOverflowXmlParser(); Siyahı qeydlər = null; Sətir başlığı = null; String url = null; Sətir xülasəsi = null; Calendar rightNow = Calendar.getInstance(); DateFormat formatlayıcısı = yeni SimpleDateFormat("MMM gg h:mmaa"); // İstifadəçinin xülasə mətnini daxil etmək üçün üstünlük təyin edib etmədiyini yoxlayır SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(bu); boolean pref = sharedPrefs.getBoolean("summaryPref", false); StringBuilder htmlString = yeni StringBuilder(); htmlString.append("

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

"); htmlString.append(" " + getResources().getString(R.string.updated) + " " + formatter.format(rightNow.getTime()) + ""); cəhd edin ( stream = downloadUrl(urlString); entries = stackOverflowXmlParser.parse(stream); // Proqramın istifadəsini bitirdikdən sonra InputStream-in bağlandığından əmin olun // istifadəsini bitir. ) nəhayət (əgər (axın != null)) ( stream.close(); ) ) // StackOverflowXmlParser Giriş obyektlərinin Siyahısını ("girişlər" adlanır) qaytarır. // Hər Entry obyekti XML lentindəki tək postu təmsil edir. // Bu bölmə hər birini birləşdirmək üçün girişlər siyahısını emal edir. HTML işarəsi ilə giriş. // Hər bir giriş UI-də isteğe bağlı olaraq // mətn xülasəsi daxil olan keçid kimi göstərilir. üçün (Entry entry: entries) ( htmlString. append("

" + entry.title + "

"); // Əgər istifadəçi xülasə mətni daxil etmək üçün üstünlük təyin edibsə, // onu ekrana əlavə edir. if (pref) ( htmlString.append(entry.summary); ) ) htmlString.toString(); ) // qaytarın URL-in sətir təsvirini nəzərə alaraq, əlaqə qurur və // giriş axını əldə edir. Private InputStream downloadUrl(String urlString) IOException atır ( URL url = yeni URL(urlString); HttpURLConnection conn = (HttpURLConnection) url.open ; conn.setReadTimeout(10000 /* millisaniyə */); conn.setConnectTimeout(15000 /* millisaniyə */); conn.setRequestMethod("GET"); conn.setDoInput(true); // conn.connect( sorğusunu başlayır ); conn.getInputStream(); ) qaytarın
Müəllif: Arseny Kapoulkine
Nəşr tarixi: 21 sentyabr 2012-ci il
Tərcümə: A.Panin
Köçürmə tarixi: 10 noyabr 2013-cü il

Giriş

XML, iyerarxik strukturlaşdırılmış sənədləri insan tərəfindən oxuna bilən mətn formatına kodlaşdırmaq üçün bir sıra qaydalar təyin edən standartlaşdırılmış işarələmə dilidir. XML standartı geniş yayılmışdır və mürəkkəb məlumat asılılığı (COLLADA) ilə həm çox yığcam sadə sənədləri (məsələn, SOAP sorğuları), həm də çox giqabaytlıq sənədləri (OpenStreetMap layihəsi tərəfindən istifadə olunur) yaratmaq üçün istifadə olunur. XML sənədlərini emal etmək üçün istifadəçilər adətən xüsusi kitabxanaya ehtiyac duyurlar: o, sənədi mətndən daxili təqdimata çevirən XML sənəd analizatorunu tətbiq etməlidir. XML standartı təhlil sürəti, istifadəçi tərəfindən oxunma qabiliyyəti və təhlil etmək üçün kod mürəkkəbliyi baxımından əvəzedicidir - buna görə də, XML sənədlərini təhlil etmək üçün sürətli sistemə malik olmaq, tətbiq məlumatlarının saxlanması formatı kimi XML-in üstünlük verilən seçiminə təsir göstərə bilər.

Bu fəsil təsvir olunan təhlil sisteminin işini yaxşılaşdırmaq və müəllifə C++ proqramlaşdırma dilindən istifadə edərək son dərəcə effektiv təhlil sistemini inkişaf etdirməyə imkan vermək üçün müxtəlif üsulları təsvir edir: pugixml. Bu üsullar XML sənədlərinin təhlili sistemi üçün istifadə olunsa da, onların əksəriyyəti digər sənədlərin təhlili sistemlərində və ya hətta tamamilə əlaqəsi olmayan proqram komponentlərində tətbiq oluna bilər (məsələn, yaddaşın idarə edilməsi alqoritmləri əlaqəli olmayan mətn sənədlərinin təhlili sistemlərində geniş istifadə olunur). ).

XML sənədlərini təhlil etmək üçün bir neçə geniş şəkildə fərqlənən yanaşmalar olduğundan və təhlil sistemi hətta XML sənədləri ilə təcrübəsi olanların da bilmədiyi əlavə addımları yerinə yetirməli olduğundan, tətbiqetmə detallarına baxmaqdan əvvəl ilk növbədə qarşıda duran vəzifəni təsvir etmək vacibdir. detal.

XML sənədlərinin təhlili sistemlərinin modelləri

XML analiz sistemlərinin müxtəlif modellərinin hər biri müəyyən situasiyalarda optimaldır və bu modellərin hər birinin öz performans və yaddaş istehlakı parametrləri var. Aşağıdakı modellər ən çox istifadə olunur:

  • SAX (XML üçün sadə API) əsasında təhliledicilərlə istifadəçi sənəd məlumat axınını giriş kimi gözləyən və "açıq teq", "teq bağla", "teq daxilindəki xarakter" kimi bir neçə geri çağırış funksiyasını təmin edən proqram komponenti ilə təmin edilir. . Təhlil sistemi sənəd məlumatlarının işlənməsi prosesində geri çağırış funksiyalarından istifadə edir. Təhlil üçün tələb olunan kontekst cari element ağacının dərinliyi ilə məhdudlaşır ki, bu da yaddaş tələblərinin əhəmiyyətli dərəcədə azaldılmasını nəzərdə tutur. Bu tip təhlil sistemi istənilən vaxt sənədin yalnız bir hissəsi mövcud olduqda axın sənədlərini emal etmək üçün istifadə edilə bilər.
  • Pull təhlili prosesin özü baxımından SAX əsaslı təhlilə bənzəyir - bir sənəd elementi bir anda emal olunur, lakin təhlil prosesinin idarə edilməsi metodu dəyişdirilir: SAX əsaslı təhlil sistemində təhlil prosesini idarə edir. sistemin özü geri çağırış funksiyalarından istifadə edir, çəkmə təhlili zamanı istifadəçi təkrarlayıcıya bənzər obyektlə təhlil prosesini idarə edir.
  • DOM (Sənəd Obyekt Modeli) təhlil sistemlərindən istifadə edərkən istifadəçi təhlil sisteminə tam bir sənədi bufer və ya mətn məlumat axını şəklində ötürür, bunun əsasında təhlil sistemi yaddaşda obyekt təsvirini yaradır. hər bir xüsusi XML elementi və ya atributu üçün ayrıca obyektlərdən istifadə etməklə sənəd elementlərinin bütöv ağacı, həmçinin etibarlı əməliyyatlar toplusu (məsələn, "bu nodeun bütün uşaqlarını əldə edin"). Pugxml kitabxanası bu modeldən istifadə edir.

Təhlil sistemi modelinin seçimi adətən sənədin ölçüsündən və strukturundan asılıdır. Pugixml DOM əsasında təhlil etdiyi üçün o, aşağıdakı sənədlər üçün effektivdir:

  • o qədər kiçikdirlər ki, tamamilə yaddaşa sığırlar,
  • keçilməsi lazım olan qovşaqlar arasında əlaqələri olan mürəkkəb bir quruluşa malikdir və ya
  • mürəkkəb sənədlərin dəyişdirilməsini tələb edir.

Pugixml-də memarlıq qərarları

Pugixml Kitabxanasının inkişafı zamanı DOM təqdimatının yaradılması probleminə çox diqqət yetirildi, çünki belə sürətli və yüngül SAX-əsaslı analizatorlar (Expat kimi) mövcud olsa da, bütün kommersiyada mövcud olan DOM əsaslı XML analizatorlarının yaradılması zamanı. pugixml (2006) ya çox yüngül, ya da çox sürətli deyildi. Buna əsaslanaraq, puixml inkişaf prosesinin əsas məqsədi DOM əsasında XML sənədləri üzərində manipulyasiyalar aparmaq üçün çox sürətli yüngül kitabxana yaratmaqdır.


bu məqalənin dərcinə yalnız məqalə müəllifinin saytına keçidlə icazə verilir

Bu yazıda böyük bir XML faylının necə təhlil ediləcəyinə dair bir nümunə göstərəcəyəm. Əgər serverinizə (hostinq) skriptin işləmə müddətini artırmaq qadağan olunmayıbsa, onda siz ən azı gigabayt ağırlığında bir XML faylını təhlil edə bilərsiniz, mən şəxsən yalnız 450 meqabayt ağırlığında ozondan olan faylları təhlil etdim.

Böyük XML fayllarını təhlil edərkən iki problem var:
1. Kifayət qədər yaddaş yoxdur.
2. Skriptin işləməsi üçün kifayət qədər ayrılmış vaxt yoxdur.

Zamanla bağlı ikinci problem, server tərəfindən qadağan edilmədiyi təqdirdə həll edilə bilər.
Ancaq yaddaş problemini həll etmək çətindir, hətta öz serverinizdən danışsaq belə, 500 meqabaytlıq faylları köçürmək o qədər də asan deyil və hətta hostinqdə və VDS-də sadəcə yaddaşı artıra bilməzsiniz.

PHP-də bir neçə daxili XML emal variantları var - SimpleXML, DOM, SAX.
Bu seçimlərin hamısı bir çox nümunə məqalələrində ətraflı təsvir edilmişdir, lakin bütün nümunələr tam XML sənədi ilə necə işləməyi göstərir.

Budur bir nümunə, XML faylından bir obyekt alırıq

İndi siz bu obyekti emal edə bilərsiniz, AMMA...
Gördüyünüz kimi, bütün XML faylı yaddaşa oxunur, sonra hər şey bir obyektdə təhlil edilir.
Yəni, bütün məlumatlar yaddaşa daxil olur və ayrılmış yaddaş kifayət deyilsə, skript dayanır.

Bu seçim böyük faylları emal etmək üçün uyğun deyil, faylı sətir-sətir oxumaq və bu məlumatları növbə ilə emal etmək lazımdır.
Eyni zamanda, etibarlılıq yoxlanışı məlumatların işlənməsi zamanı da həyata keçirilir, buna görə də siz geri qaytara bilməlisiniz, məsələn, qeyri- etibarlı XML faylı vəziyyətində daxil edilmiş bütün verilənlər bazasını silmək və ya ikisini etmək lazımdır. fayldan keçir, əvvəlcə etibarlılıq üçün oxuyur, sonra məlumatları emal etmək üçün oxuyur.

Böyük XML faylını təhlil etməyin nəzəri nümunəsi budur.
Bu skript fayldan bir simvol oxuyur, bu məlumatları bloklara toplayır və XML təhlilçisinə göndərir.
Bu yanaşma yaddaş problemini tamamilə həll edir və yük yaratmır, ancaq zamanla problemi daha da artırır. Zamanla problemi necə həll etməyə çalışmaq, aşağıda oxuyun.

webi_xml funksiyası($fayl)
{

########
### verilənlərlə işləmə funksiyası

{
$data çap edin;
}
############################################



{
çap $name;
çap_r($attr);
}


## bağlama etiketi funksiyası
funksiya endElement ($parser , $name )
{
çap $name;
}
############################################

($xml_parser , "məlumat" );

// faylı açın
$fp = fopen($fayl , "r" );

$perviy_vxod = 1 ; $data = "" ;



{

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


if($simvol != ">" ) (davam et;)


əks-səda "

fasilə;
}

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

webi_xml("1.xml");

?>

Bu misalda mən hər şeyi bir webi_xml () funksiyasına qoyuram və onun çağırışı ən aşağıda görünür.
Skript özü üç əsas funksiyadan ibarətdir:
1. startElement() teqinin açılışını tutan funksiya
2. endElement() teqinin bağlanmasını tutan funksiya
3. Və qəbul funksiyası data() .

Tutaq ki, 1.xml faylının məzmunu hansısa reseptdir



< title >sadə çörək
< ingredient amount = "3" unit = "стакан" >un
< ingredient amount = "0.25" unit = "грамм" >Maya
< ingredient amount = "1.5" unit = "стакан" >ilıq su
< ingredient amount = "1" unit = "чайная ложка" >Duz
< instructions >
< step > Bütün maddələri qarışdırın və hərtərəfli yoğurun.
< step > Bir parça ilə örtün və isti otaqda bir saat buraxın.
< step > Yenidən yoğurun, çörək qabına qoyun və sobaya qoyun.
< step > Sayt saytına daxil olun


Bir çağırışla başlayırıq ümumi funksiya webi_xml("1.xml");
Bundan əlavə, bu funksiyada təhliledici işə salınır və bütün teq adları böyük hərflərə çevrilir ki, bütün teqlərin hərfləri eyni olsun.

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

İndi etiketin açılmasını, bağlanmasını və məlumatların işlənməsini tutmaq üçün hansı funksiyaların işləyəcəyini müəyyənləşdiririk

xml_set_element_handler($xml_parser , "startElement" , "endElement" );
xml_set_character_data_handler($xml_parser , "məlumat" );

Sonra müəyyən edilmiş faylın açılması gəlir, fayl üzərində hər dəfə bir simvol təkrarlanır və simvol tapılana qədər hər simvol simli dəyişənə əlavə edilir. > .
Bu fayla ilk girişdirsə, faylın əvvəlində lazımsız olan hər şey yol boyu silinəcək, qarşısında duran hər şey , bu XML etiketi ilə başlamalıdır.
İlk dəfə simli dəyişən sətir toplayacaq

Və təhlilçiyə göndərin
xml_parse ($xml_parser , $data , feof ($fp ));
Verilənləri emal etdikdən sonra sətir dəyişəni sıfırlanır və verilənlərin sətirdə toplanması yenidən başlayır və sətir ikinci dəfə formalaşır.

Üçüncüdə
</b><br>dördüncüdə <br><b>sadə çörək

Nəzərə alın ki, sətir dəyişəni həmişə tamamlanmış teq tərəfindən formalaşır > və məsələn, ayrıştırıcıya verilənlərlə açıq və qapalı teqləri göndərmək lazım deyil
sadə çörək
Bu işləyici üçün bütöv bir pozulmamış teq, ən azı bir açıq teq, növbəti mərhələdə isə qapalı teq almaq vacibdir və ya dərhal faylın 1000 sətirini alması vacibdir, fərqi yoxdur, əsas odur ki, teq məsələn, qırılmır

le>Sadə çörək
Beləliklə, məlumatı işləyiciyə göndərmək mümkün deyil, çünki etiket qırılıb.
Siz işləyiciyə məlumat göndərmək üçün öz üsulunuzu tapa bilərsiniz, məsələn, 1 meqabayt məlumat toplayın və sürəti artırmaq üçün onu işləyiciyə göndərin, sadəcə etiketlərin həmişə bitdiyinə və məlumatların qırıla biləcəyinə əmin olun.
Sadə</b><br><b>çörək

Beləliklə, hissə-hissə, istədiyiniz kimi göndərə bilərsiniz böyük fayl idarəçiyə.

İndi bu məlumatların necə işləndiyinə və necə əldə ediləcəyinə baxaq.

Açılış etiketləri xüsusiyyətindən başlayaraq startElement ($parser , $name , $attrs )
Tutaq ki, emal xəttinə çatıb
< ingredient amount = "3" unit = "стакан" >un
Onda funksiya daxilində $name dəyişəni bərabər olacaq tərkib hissəsi yəni açıq etiketin adı (məsələ hələ etiketin bağlanmasına çatmayıb).
Həmçinin bu halda, bu $attrs teqinin atributları silsiləsi əlçatan olacaq və orada verilənlər olacaq. məbləğ = "3" və vahid = "şüşə".

Bundan sonra funksiya tərəfindən açıq etiketin məlumatları emal edildi data ($parser , $data )
$data dəyişəni açılış və bağlanış teqi arasında olan hər şeyi ehtiva edəcək, bizim vəziyyətimizdə bu Muk mətnidir.

Və sətirimizin funksiya tərəfindən işlənməsi tamamlandı endElement ($parser, $name)
Bu qapalı etiketin adıdır, bizim vəziyyətimizdə $name bərabər olacaq tərkib hissəsi

Və bundan sonra hər şey yenidən tam dövrəyə girdi.

Yuxarıdakı nümunə yalnız XML emal prinsipini nümayiş etdirir, lakin real tətbiq üçün onu yekunlaşdırmaq lazımdır.
Adətən verilənlər bazasına məlumat daxil etmək üçün böyük XML-i təhlil etməlisiniz və məlumatların düzgün işlənməsi üçün məlumatın hansı açıq teqə aid olduğunu, hansı teq yuvasının səviyyəsini və yuxarıdakı iyerarxiyada hansı teqlərin açıq olduğunu bilməlisiniz. Bu məlumatla faylı heç bir problem olmadan düzgün emal edə bilərsiniz.
Bunu etmək üçün açıq etiketlər, yuvalar və məlumatlar haqqında məlumat toplayan bir neçə qlobal dəyişən təqdim etməlisiniz.
Burada istifadə edilə bilən bir nümunə var

webi_xml funksiyası($fayl)
{
qlobal $webi_depth ; // yuvalama dərinliyini izləmək üçün sayğac
$webi_depth = 0 ;
qlobal $webi_tag_open ; // hazırda açıq teqlər massivindən ibarət olacaq
$webi_tag_open = massiv();
qlobal $webi_data_temp ; // bu massiv bir teq məlumatını ehtiva edəcək

####################################################
### verilənlərlə işləmə funksiyası
funksiya datası ($parser , $data )
{
qlobal $webi_depth ;
qlobal $webi_tag_open ;
qlobal $webi_data_temp ;
// yuvalanmış və hazırda açılmış teq ilə massivə məlumat əlavə edin
$webi_data_temp [ $webi_depth ][ $webi_tag_open [ $webi_depth ]][ "data" ].= $data ;
}
############################################

####################################################
### açılış etiketi funksiyası
startElement funksiyası ($parser , $name , $attrs )
{
qlobal $webi_depth ;
qlobal $webi_tag_open ;
qlobal $webi_data_temp ;

// əgər yuva səviyyəsi artıq sıfır deyilsə, onda bir teq artıq açıqdır
// və ondan alınan məlumatlar artıq massivdədir, siz onları emal edə bilərsiniz
əgər ($webi_depth)
{




" ;

çap"
" ;
print_r($webi_tag_open); // açıq teqlər massivi
çap"


" ;

// verilənləri emal etdikdən sonra yaddaşı boşaltmaq üçün onları silin
unset($GLOBALS [ "webi_data_temp" ][ $webi_depth ]);
}

// indi növbəti etiketin açılmasına başlanılıb və növbəti mərhələdə sonrakı emal baş verəcək
$webi_depth++; // yuva qurmağı artırmaq

$webi_tag_open [ $webi_depth ]= $name ; // məlumat massivinə açıq teq əlavə edin
$webi_data_temp [ $webi_depth ][ $name ][ "attrs" ]= $attrs ; // indi teq atributları əlavə edin

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

#################################################
## bağlama etiketi funksiyası
endElement funksiyası ($parser, $name) (
qlobal $webi_depth ;
qlobal $webi_tag_open ;
qlobal $webi_data_temp ;

// verilənlərin emalı burada başlayır, məsələn, verilənlər bazasına əlavə etmək, faylda saxlamaq və s.
// $webi_tag_open yuva səviyyəsinə görə açıq teqlər zəncirindən ibarətdir
// məsələn, $webi_tag_open[$webi_depth] məlumatı hazırda emal olunan açıq teqdən ibarətdir
// $webi_depth teq yuva səviyyəsi
// $webi_data_temp[$webi_depth][$webi_tag_open[$webi_depth]]["attrs"] teq atributları massivi
// $webi_data_temp[$webi_depth][$webi_tag_open[$webi_depth]]["data"] teq datası

"Məlumat" çap edin. $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" ]);
çap"
" ;
print_r($webi_tag_open);
çap"


" ;

Ayarlanmadı($GLOBALS [ "webi_data_temp" ]); // verilənləri emal etdikdən sonra teq bağlandığından massivi bütövlükdə verilənlərlə birlikdə silin
unset($GLOBALS [ "webi_tag_open" ][ $webi_depth ]); // bu açılan teq haqqında məlumatı silin... bağlandığı üçün

$webi_depth --; // yuva qurmağı azaltmaq
}
############################################

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

// teqləri açıb bağlayarkən hansı funksiyaların işləyəcəyini müəyyənləşdirin
xml_set_element_handler($xml_parser , "startElement" , "endElement" );

// verilənlərlə işləmək üçün funksiya təyin edin
xml_set_character_data_handler($xml_parser , "məlumat" );

// faylı açın
$fp = fopen($fayl , "r" );

$perviy_vxod = 1 ; // fayla ilk girişi yoxlamaq üçün bayraq
$data = "" ; // burada biz fayldan verilənlərin hissələrini toplayırıq və xml təhlilçisinə göndəririk

// tapılan faylın sonuna qədər döngə
isə (! feof ($fp ) və $fp )
{
$simvol = fgetc($fp); // fayldan bir simvol oxumaq
$data .= $simvol ; // bu simvolu göndəriləcək verilənlərə əlavə edin

// əgər simvol son teq deyilsə, döngənin əvvəlinə qayıdın və verilənlərə daha bir simvol əlavə edin və son teq tapılana qədər davam edin.
if($simvol != ">" ) (davam et;)
// əgər bağlanma teqi tapılıbsa, indi bu toplanmış məlumatları emala göndərin

// bunun fayldakı ilk giriş olub olmadığını yoxlayın, sonra etiketdən əvvəl hər şeyi silin// çünki bəzən XML başlamazdan əvvəl zibil ola bilər (yalnız redaktorlar və ya fayl başqa serverdən skript tərəfindən qəbul edilmişdir)
if($perviy_vxod ) ( $data = strstr ($data , "

// indi məlumatları xml təhlilçisinə atırıq
əgər (! xml_parse ($xml_parser , $data , feof ($fp ))) (

// burada etibarlılıq üçün səhvləri emal edə və əldə edə bilərsiniz...
// xəta ilə qarşılaşan kimi təhlil dayandırılır
əks-səda "
XML xətası: " .xml_error_string (xml_get_error_code ($xml_parser ));
əks-səda "sətirdə". xml_get_current_line_number($xml_parser );
fasilə;
}

// təhlil etdikdən sonra toplanmış məlumatları döngənin növbəti addımı üçün atırıq.
$data = "" ;
}
fclose($fp);
xml_parser_free($xml_parser );
// qlobal dəyişənləri silin
unset($GLOBALS [ "webi_depth" ]);
unset($GLOBALS [ "webi_tag_open" ]);
unset($GLOBALS [ "webi_data_temp" ]);

webi_xml("1.xml");

?>

Bütün nümunə şərhlərlə müşayiət olundu, indi sınaqdan keçirin və sınaqdan keçirin.
Nəzərə alın ki, verilənlərin manipulyasiyası funksiyasında məlumatlar sadəcə massivə daxil edilmir, "" istifadə edərək əlavə edilir. .=" çünki məlumatlar bütöv bir formada gəlməyə bilər və sadəcə bir tapşırıq versəniz, vaxtaşırı məlumatı hissə-hissə alacaqsınız.

Yaxşı, hamısı budur, indi istənilən ölçülü bir faylı emal edərkən kifayət qədər yaddaş olacaq, lakin skriptin işləmə müddəti bir neçə yolla artırıla bilər.
Skriptin əvvəlinə funksiya daxil edin
təyin_vaxt_limiti(6000);
və ya
ini_set("maksimum_icra_vaxtı", "6000" );

Və ya .htaccess faylına mətn əlavə edin
php_value max_execution_time 6000

Bu nümunələr skriptin işləmə müddətini 6000 saniyəyə qədər artıracaq.
Siz yalnız söndürülmüş təhlükəsiz rejimdə vaxtı bu şəkildə artıra bilərsiniz.

Əgər php.ini-ni redaktə etmək imkanınız varsa, vaxtı artıra bilərsiniz
maksimum_icra_zamanı = 6000

Məsələn, masterhost hostinqində, bu yazı zamanı, əlil olmasına baxmayaraq, skript vaxtının artırılması qadağandır. Təhlükəsizlik rejimi, ancaq peşəkarsınızsa, php-nizi masterhost üzərində qura bilərsiniz, lakin bu, bu məqalədə deyil.