IlmHamroh
Python kursi/Malumot formatlari5/8-dars20 daqiqa
Mundarija (23)

16.5-dars: XML

16-QISM — MA'LUMOT FORMATLARI · 5-dars


1. Kirish va motivatsiya

XML — "kengaytiriladigan belgilash tili". JSON keng tarqalguncha u ma'lumot almashishning asosiy formati edi va bugun ham ko'p joyda yashaydi: RSS/Atom lentalar, SOAP veb-xizmatlar, Office hujjatlari (.docx, .xlsx — ichida XML), Android va Java sozlamalari, SVG, sitemap, bank va davlat integratsiyalari. XML ni o'qiy va yoza bilish — real integratsiya ishida zarur ko'nikma.

Real vaziyat. Bir jamoa hamkor bankdan kunlik tranzaksiya faylini XML ko'rinishida qabul qilardi. Boshida hammasi oddiy ko'rindi — xml.etree.ElementTree bilan o'qildi. Keyin uch muammo ketma-ket chiqdi. Birinchisi: fayl <Document xmlns="urn:iso:std:iso:20022..."> bilan boshlanardi — nom fazosi (namespace), va root.find("Tranzaksiya") hech narsa topmadi, chunki teg aslida {urn:iso...}Tranzaksiya edi. Ikkinchisi: fayl kattalashib 500 MB ga yetdi va ET.parse butun daraxtni xotiraga yuklab, serverni cho'ktirdi. Uchinchisi — eng jiddiysi: xavfsizlik auditi "billion laughs" hujumini ko'rsatdi — bir necha qatorli XML minglab marta kengayib, xotirani portlatishi mumkin edi.

Bu darsda XML ni ElementTree bilan o'qish va yozishni, nom fazolarini, oqimli tahlilni va — eng muhimi — XML ga xos xavfsizlik xatarlarini o'rganamiz.

Bu darsda:

  • fromstring/parse, find/findall/findtext, XPath qism to'plami
  • Atributlar, text va tail
  • Daraxt qurish: Element, SubElement, tostring, indent
  • Nom fazolari — {uri}teg va register_namespace
  • Xavfsizlik: entity kengayishi ("billion laughs"), XXE
  • Oqimli tahlil: iterparse + elem.clear()
  • ParseError va belgi ekranlash
  • Amaliy: RSS lentani o'qib qayta ishlash

2. Nazariya — chuqur tushuntirish

2.1. XML tuzilishi

xml
<?xml version="1.0" encoding="UTF-8"?>
<katalog>
  <kitob id="1" til="uz">
    <nom>Oʻtkan kunlar</nom>
    <narx valyuta="UZS">45000</narx>
  </kitob>
</katalog>
Tushuncha Misol
Element (teg) <kitob>...</kitob>
Atribut id="1"
Matn (text) <nom> ichidagi Oʻtkan kunlar
Ildiz element <katalog>
Ichma-ichlik kitob → nom, narx

JSON dan farqi: XML da atribut va element farqi bor, matn va bolalar aralashishi mumkin, tartib saqlanadi, turlar yo'q (hammasi matn).

2.2. O'qish va navigatsiya

Funksiya Nima qiladi
ET.fromstring(matn) Satrdan → ildiz Element
ET.parse(fayl) Fayldan → ElementTree (.getroot())
elem.find(yol) Birinchi mos element (yoki None)
elem.findall(yol) Barcha mos elementlar ro'yxati
elem.findtext(yol) Mos elementning matni
elem.iterfind(yol) Iterator (katta daraxt uchun)
elem.get("atr") Atribut qiymati (yoki None)

Element — ro'yxatga o'xshaydi: len(elem) — bolalar soni, for bola in elem, elem[0].

2.3. XPath qism to'plami

ElementTree XPath ning kichik qismini qo'llaydi:

Ifoda Ma'nosi
nom Bevosita nom bolalari
.//nom Istalgan chuqurlikdagi nom
kitob/nom kitob ichidagi nom
kitob[@id='2'] id atributi 2 bo'lgan kitob
kitob[narx] narx bolasi bor kitob
* Har qanday bola
[1] Birinchi ( 1 dan, XPath odati)

To'liq XPath emas: //, funksiyalar, o'qlar (ancestor::) yo'q — kerak bo'lsa lxml.

2.4. text va tail

xml
<a>matn<b/>quyruq</a>
Atribut Qiymati
a.text "matn"
b.tail "quyruq" — b dan keyingi matn

Aralash kontent (matn + elementlar) da tail ni unutish — matnni yo'qotishning keng tarqalgan sababi.

2.5. Daraxt qurish va yozish

python
ildiz = ET.Element("katalog")
kitob = ET.SubElement(ildiz, "kitob", id="1")
ET.SubElement(kitob, "nom").text = "Sarob"
ET.indent(ildiz)                                  # chiroyli otstup (3.9+)
matn = ET.tostring(ildiz, encoding="unicode")     # str; encoding="utf-8" → bytes
Funksiya Izoh
ET.Element(teg, atr=...) Yangi element
ET.SubElement(ota, teg) Bola qo'shadi va qaytaradi
elem.set("atr", qiymat) Atribut o'rnatadi
elem.append(bola) Element qo'shadi
ET.indent(elem) Bo'shliq bilan formatlaydi
ET.tostring(elem, encoding=...) Serializatsiya ("unicode" → str, aks holda bytes)
ET.ElementTree(elem).write(fayl, ...) Faylga; xml_declaration=True

<, >, &, " belgilar avtomatik ekranlanadi (&lt; va h.k.) — ularni qo'lda almashtirmang.

2.6. Nom fazolari (namespaces)

xml
<r xmlns="http://ex.uz/ns" xmlns:m="http://ex.uz/meta">
  <a m:id="7">x</a>
</r>

ElementTree nom fazosini teg nomiga {uri}teg ko'rinishida qo'shadi:

Ko'rinish Qiymati
r.tag {http://ex.uz/ns}r
Qidirish r.find("{http://ex.uz/ns}a")
NS li atribut a.get("{http://ex.uz/meta}id")

Amaliy usul — nom fazolarini lug'atga olib, find ga namespaces= berish:

python
NS = {"": "http://ex.uz/ns", "m": "http://ex.uz/meta"}
r.find("a", NS)              # bo'sh prefiks ham ishlaydi (3.8+)

Yozishda ET.register_namespace(prefiks, uri) — chiqishda chiroyli prefiks uchun.

2.7. XML xavfsizligi

XML ma'lumotni emas, hujjatni tasvirlaydi — va DTD (hujjat ta'rifi) orqali entity (belgilangan qisqartma) larni qo'llaydi. Bu ikki hujum turini keltirib chiqaradi:

1. Entity kengayishi ("billion laughs" / eksponensial portlash). Bir-biriga havola qiluvchi entity lar eksponensial kengayadi: 10 qatorli XML gigabaytlab xotira talab qilishi mumkin.

xml
<!ENTITY lol0 "lol">
<!ENTITY lol1 "&lol0;&lol0;">     <!-- har daraja ikki baravar -->

2. XXE (XML External Entity). Tashqi entity fayl yoki URL ni o'qishga urinadi:

xml
<!ENTITY x SYSTEM "file:///etc/passwd">

Python 3.14 stdlib holati:

Xatar xml.etree.ElementTree
Tashqi umumiy entity (XXE, fayl o'qish) Hal qilinmaydi — xavfsiz sukut
Tashqi DTD yuklash Yuklanmaydi
Ichki entity kengayishi (billion laughs) Kengayadi — DoS mumkin

Xulosa: stdlib XXE dan himoyalangan, lekin entity kengayishidan emas. Ishonchsiz XML uchun — defusedxml kutubxonasi (barcha entity va DTD ni bloklaydi).

2.8. Oqimli tahlil (iterparse)

Katta fayllarni butun daraxtni yuklamasdan:

python
for hodisa, elem in ET.iterparse(fayl, events=("end",)):
    if elem.tag == "yozuv":
        ishlash(elem)
        elem.clear()                              # ⭐ xotirani bo'shatish

elem.clear() bo'lmasa daraxt baribir xotirada to'planadi. Bu — katta XML ni qayta ishlashning yagona to'g'ri yo'li.

2.9. Xatolar

Xato Sabab
ParseError: mismatched tag Yopilmagan/noto'g'ri teg; line, column bor
ParseError: not well-formed Noto'g'ri belgi
find None qaytaradi Nom fazosi hisobga olinmagan

3. Tez ma'lumotnoma

python
import xml.etree.ElementTree as ET

ildiz = ET.fromstring(matn)                        # yoki ET.parse(fayl).getroot()
for kitob in ildiz.findall(".//kitob[@til='uz']"):
    print(kitob.get("id"), kitob.findtext("nom"))

NS = {"a": "http://ex.uz/ns"}
ildiz.find("a:element", NS)

yangi = ET.Element("root")
ET.SubElement(yangi, "item", id="1").text = "qiymat"
ET.indent(yangi)
matn = ET.tostring(yangi, encoding="unicode")

for _, elem in ET.iterparse(katta_fayl, events=("end",)):   # oqimli
    if elem.tag == "yozuv":
        ...; elem.clear()

Qoidalar

nom fazosi bor: {uri}teg yoki namespaces=
katta fayl: iterparse + elem.clear()
ishonchsiz XML: defusedxml
belgilarni qo'lda ekranlamang
find None qaytarsa — avval nom fazosini tekshiring
tail ni unutmang (aralash kontent)

4. Batafsil misollar

Misol 1 — O'qish, navigatsiya va XPath

python
"""fromstring; find/findall/findtext; atributlar; XPath: shart, indeks, atribut; text va tail; Element ro'yxatga o'xshashligi."""

import xml.etree.ElementTree as ET

XML = """<?xml version="1.0" encoding="UTF-8"?>
<katalog>
  <kitob id="1" til="uz">
    <nom>Oʻtkan kunlar</nom>
    <muallif>Abdulla Qodiriy</muallif>
    <narx valyuta="UZS">45000</narx>
  </kitob>
  <kitob id="2" til="uz">
    <nom>Sarob</nom>
    <muallif>Abdulla Qahhor</muallif>
    <narx valyuta="UZS">38000</narx>
  </kitob>
  <kitob id="3" til="ru">
    <nom>Voyna i mir</nom>
    <muallif>Lev Tolstoy</muallif>
  </kitob>
</katalog>"""


def main() -> None:
    ildiz = ET.fromstring(XML)
    print(f"=== 1. Ildiz ===")
    print(f"  teg: {ildiz.tag}, bolalar soni: {len(ildiz)}")

    print("\n=== 2. Aylanish va atributlar ===")
    for kitob in ildiz.findall("kitob"):
        narx = kitob.findtext("narx", default="—")
        valyuta = kitob.find("narx").get("valyuta") if kitob.find("narx") is not None else ""
        print(f"  #{kitob.get('id')} [{kitob.get('til')}] {kitob.findtext('nom'):18} {narx} {valyuta}")

    print("\n=== 3. XPath ===")
    print(f"  barcha nomlar: {[e.text for e in ildiz.iterfind('.//nom')]}")
    muallif2 = ildiz.find(".//kitob[@id='2']/muallif")
    print(f"  id=2 muallifi: {muallif2.text}")
    print(f"  narxi bor kitoblar: {[k.get('id') for k in ildiz.findall('.//kitob[narx]')]}")
    uzbekcha = [k.findtext("nom") for k in ildiz.findall(".//kitob[@til='uz']")]
    print(f"  uzbekcha kitoblar: {uzbekcha}")
    print(f"  birinchi kitob nomi: {ildiz.find('kitob[1]/nom').text}")

    print("\n=== 4. Yo'q qiymatlar ===")
    ruscha = ildiz.find(".//kitob[@id='3']")
    print(f"  narx elementi: {ruscha.find('narx')}")
    print(f"  findtext sukut bilan: {ruscha.findtext('narx', default='narx korsatilmagan')}")

    print("\n=== 5. text va tail (aralash kontent) ===")
    aralash = ET.fromstring("<xat>Hurmatli <ism>Aziz</ism>, xush kelibsiz <b>Wisar</b> ga!</xat>")
    print(f"  text: {aralash.text!r}")
    for bola in aralash:
        print(f"  <{bola.tag}> text={bola.text!r} tail={bola.tail!r}")
    print(f"  butun matn: {''.join(aralash.itertext())!r}")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Ildiz ===
  teg: katalog, bolalar soni: 3

=== 2. Aylanish va atributlar ===
  #1 [uz] Oʻtkan kunlar      45000 UZS
  #2 [uz] Sarob              38000 UZS
  #3 [ru] Voyna i mir        —

=== 3. XPath ===
  barcha nomlar: ['Oʻtkan kunlar', 'Sarob', 'Voyna i mir']
  id=2 muallifi: Abdulla Qahhor
  narxi bor kitoblar: ['1', '2']
  uzbekcha kitoblar: ['Oʻtkan kunlar', 'Sarob']
  birinchi kitob nomi: Oʻtkan kunlar

=== 4. Yo'q qiymatlar ===
  narx elementi: None
  findtext sukut bilan: narx korsatilmagan

=== 5. text va tail (aralash kontent) ===
  text: 'Hurmatli '
  <ism> text='Aziz' tail=', xush kelibsiz '
  <b> text='Wisar' tail=' ga!'
  butun matn: 'Hurmatli Aziz, xush kelibsiz Wisar ga!'

Nima ko'rsatdi: 2.2, 2.3, 2.4-bo'limlar.

Misol 2 — Daraxt qurish va nom fazolari

python
"""Element/SubElement bilan qurish; set; belgi ekranlash; indent; tostring; nom fazolari {uri}teg; namespaces= lug'at; register_namespace."""

import xml.etree.ElementTree as ET


def main() -> None:
    print("=== 1. Daraxt qurish ===")
    katalog = ET.Element("katalog", versiya="1.0")
    for id_, nom, narx in [(1, "Sarob", 38000), (2, "Kecha va kunduz", 42000)]:
        kitob = ET.SubElement(katalog, "kitob", id=str(id_))
        ET.SubElement(kitob, "nom").text = nom
        ET.SubElement(kitob, "narx", valyuta="UZS").text = str(narx)
    ET.indent(katalog, space="  ")
    print(ET.tostring(katalog, encoding="unicode"))

    print("=== 2. ⭐ Belgi ekranlash ===")
    izoh = ET.Element("izoh")
    izoh.text = "5 < 10 & \"tirnoq\" > belgilar"
    izoh.set("shart", "a < b")
    print(f"  {ET.tostring(izoh, encoding='unicode')}")
    qaytgan = ET.fromstring(ET.tostring(izoh, encoding="unicode"))
    print(f"  qaytib o'qilganda asl matn: {qaytgan.text!r}")

    print("\n=== 3. ⚠️ Nom fazolari — o'qish ===")
    ns_xml = """<hujjat xmlns="urn:iso:20022" xmlns:b="urn:bank:meta">
      <tranzaksiya b:id="TXN-7">
        <summa>1500000</summa>
      </tranzaksiya>
    </hujjat>"""
    ildiz = ET.fromstring(ns_xml)
    print(f"  ildiz.tag: {ildiz.tag}")
    print(f"  to'liq nom bilan: {ildiz.find('{urn:iso:20022}tranzaksiya') is not None}")
    NS = {"": "urn:iso:20022", "b": "urn:bank:meta"}
    tranzaksiya = ildiz.find("tranzaksiya", NS)
    print(f"  namespaces= lug'at bilan: summa={tranzaksiya.findtext('summa', namespaces=NS)}")
    print(f"  NS li atribut: {tranzaksiya.get('{urn:bank:meta}id')}")
    print(f"  find('tranzaksiya') NS siz: {ildiz.find('tranzaksiya')}  ← None, chunki NS hisobga olinmadi")

    print("\n=== 4. Nom fazosi bilan yozish ===")
    ET.register_namespace("", "urn:iso:20022")
    ET.register_namespace("b", "urn:bank:meta")
    yangi = ET.Element("{urn:iso:20022}hujjat")
    t = ET.SubElement(yangi, "{urn:iso:20022}tranzaksiya")
    t.set("{urn:bank:meta}id", "TXN-9")
    ET.SubElement(t, "{urn:iso:20022}summa").text = "2000000"
    print(ET.tostring(yangi, encoding="unicode"))


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Daraxt qurish ===
<katalog versiya="1.0">
  <kitob id="1">
    <nom>Sarob</nom>
    <narx valyuta="UZS">38000</narx>
  </kitob>
  <kitob id="2">
    <nom>Kecha va kunduz</nom>
    <narx valyuta="UZS">42000</narx>
  </kitob>
</katalog>
=== 2. ⭐ Belgi ekranlash ===
  <izoh shart="a &lt; b">5 &lt; 10 &amp; "tirnoq" &gt; belgilar</izoh>
  qaytib o'qilganda asl matn: '5 < 10 & "tirnoq" > belgilar'

=== 3. ⚠️ Nom fazolari — o'qish ===
  ildiz.tag: {urn:iso:20022}hujjat
  to'liq nom bilan: True
  namespaces= lug'at bilan: summa=1500000
  NS li atribut: TXN-7
  find('tranzaksiya') NS siz: None  ← None, chunki NS hisobga olinmadi

=== 4. Nom fazosi bilan yozish ===
<hujjat xmlns="urn:iso:20022" xmlns:b="urn:bank:meta"><tranzaksiya b:id="TXN-9"><summa>2000000</summa></tranzaksiya></hujjat>

Nima ko'rsatdi: 2.5, 2.6-bo'limlar.

Misol 3 — Xavfsizlik va oqimli tahlil

python
"""Entity kengayishi (billion laughs) eksponensial o'sadi; tashqi entity (XXE) stdlib da hal qilinmaydi; tashqi DTD yuklanmaydi; iterparse + clear bilan oqimli tahlil."""

import xml.etree.ElementTree as ET


def billion_laughs(daraja: int) -> str:
    entitylar = "".join(f'  <!ENTITY lol{i} "&lol{i - 1};&lol{i - 1};">\n' for i in range(1, daraja + 1))
    return (f'<?xml version="1.0"?>\n<!DOCTYPE l [\n  <!ENTITY lol0 "lol">\n'
            f'{entitylar}]>\n<l>&lol{daraja};</l>')


def main() -> None:
    print("=== 1. ⚠️ Entity kengayishi (billion laughs) ===")
    for daraja in (4, 8, 12):
        ildiz = ET.fromstring(billion_laughs(daraja))
        print(f"  daraja {daraja:2}: {len('lol')}×2^{daraja} = {len(ildiz.text):6} belgi (XML manba ~{daraja + 4} qator)")
    print("  ⚠️ har daraja ikki baravar — 30-daraja gigabaytlarga yetadi (xotira DoS)")

    print("\n=== 2. ✅ XXE — tashqi entity hal qilinmaydi ===")
    xxe = ('<?xml version="1.0"?>\n<!DOCTYPE r [ <!ENTITY x SYSTEM "file:///maxfiy.txt"> ]>\n<r>&x;</r>')
    try:
        ET.fromstring(xxe)
    except ET.ParseError as xato:
        print(f"  tashqi entity: {str(xato).split(':')[0]}")
        print("  ⭐ fayl o'qilmadi — stdlib tashqi entity ni hal qilmaydi (XXE dan xavfsiz)")

    print("\n=== 3. ✅ Tashqi DTD yuklanmaydi ===")
    ext_dtd = '<?xml version="1.0"?>\n<!DOCTYPE r SYSTEM "http://mavjud-emas.invalid/x.dtd">\n<r>ok</r>'
    print(f"  tarmoqqa chiqmadi, natija: {ET.fromstring(ext_dtd).text}")

    print("\n=== 4. Xavfsiz yechim ===")
    print("  ishonchsiz XML uchun: pip install defusedxml")
    print("  import defusedxml.ElementTree as ET  → entity va DTD bloklanadi")

    print("\n=== 5. Oqimli tahlil (iterparse) ===")
    katta = "<lenta>" + "".join(f"<yozuv id='{i}'><ball>{i * 10}</ball></yozuv>" for i in range(1, 6)) + "</lenta>"
    import io
    jami = 0
    korilgan = []
    for hodisa, elem in ET.iterparse(io.StringIO(katta), events=("end",)):
        if elem.tag == "yozuv":
            jami += int(elem.findtext("ball"))
            korilgan.append(elem.get("id"))
            elem.clear()                          # ⭐ xotirani bo'shatish
    print(f"  qayta ishlangan yozuvlar: {korilgan}, jami ball: {jami}")
    print("  ⚠️ elem.clear() bo'lmasa butun daraxt xotirada to'planadi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. ⚠️ Entity kengayishi (billion laughs) ===
  daraja  4: 3×2^4 =     48 belgi (XML manba ~8 qator)
  daraja  8: 3×2^8 =    768 belgi (XML manba ~12 qator)
  daraja 12: 3×2^12 =  12288 belgi (XML manba ~16 qator)
  ⚠️ har daraja ikki baravar — 30-daraja gigabaytlarga yetadi (xotira DoS)

=== 2. ✅ XXE — tashqi entity hal qilinmaydi ===
  tashqi entity: undefined entity &x;
  ⭐ fayl o'qilmadi — stdlib tashqi entity ni hal qilmaydi (XXE dan xavfsiz)

=== 3. ✅ Tashqi DTD yuklanmaydi ===
  tarmoqqa chiqmadi, natija: ok

=== 4. Xavfsiz yechim ===
  ishonchsiz XML uchun: pip install defusedxml
  import defusedxml.ElementTree as ET  → entity va DTD bloklanadi

=== 5. Oqimli tahlil (iterparse) ===
  qayta ishlangan yozuvlar: ['1', '2', '3', '4', '5'], jami ball: 150
  ⚠️ elem.clear() bo'lmasa butun daraxt xotirada to'planadi

Nima ko'rsatdi: 2.7, 2.8-bo'limlar.

Misol 4 — Amaliy: RSS lentani o'qib qayta ishlash

Ko'p sayt yangiliklarni RSS (XML) formatida beradi. Bizga hamkorlarning lentalarini o'qib, sanasi bo'yicha saralab, <content:encoded> (nom fazoli) va oddiy maydonlarni ajratib, ichki hisobotga aylantirish kerak. Lenta tashqi manbadan kelgani uchun uni ishonchsiz deb qaraymiz: tuzilishni tekshiramiz, yetishmayotgan maydonlarga bardosh beramiz va natijani JSON 16.2-bob ga chiqaramiz.

python
"""RSS/Atom-ga o'xshash XML: nom fazolari, findtext sukut bilan, sana tahlili va saralash, aralash maydonlar, ichki hisobotga (JSON) aylantirish."""

import json
import xml.etree.ElementTree as ET
from datetime import datetime

RSS = """<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Wisar Blog</title>
    <item>
      <title>Python 3.14 chiqdi</title>
      <link>https://wisar.uz/p/314</link>
      <pubDate>2026-09-15</pubDate>
      <dc:creator>Aziz</dc:creator>
      <category>python</category>
      <category>yangilik</category>
      <content:encoded>Yangi versiyada &lt;b&gt;bepul-tred&lt;/b&gt; rejimi bor.</content:encoded>
    </item>
    <item>
      <title>Type hints amaliyoti</title>
      <link>https://wisar.uz/p/types</link>
      <pubDate>2026-09-17</pubDate>
      <dc:creator>Malika</dc:creator>
      <category>python</category>
    </item>
    <item>
      <title>Sarlavhasiz qoralama</title>
      <pubDate>notogri-sana</pubDate>
    </item>
  </channel>
</rss>"""

NS = {"content": "http://purl.org/rss/1.0/modules/content/",
      "dc": "http://purl.org/dc/elements/1.1/"}


def sana_ol(matn: str | None) -> datetime | None:
    if not matn:
        return None
    try:
        return datetime.strptime(matn.strip(), "%Y-%m-%d")
    except ValueError:
        return None


def maqola_ol(item: ET.Element) -> dict:
    sana = sana_ol(item.findtext("pubDate"))
    return {
        "sarlavha": (item.findtext("title") or "").strip() or "(sarlavhasiz)",
        "havola": item.findtext("link"),
        "sana": sana.date().isoformat() if sana else None,
        "muallif": item.findtext("dc:creator", namespaces=NS),
        "teglar": [c.text for c in item.findall("category")],
        "kontent_bormi": item.find("content:encoded", NS) is not None,
    }


def main() -> None:
    ildiz = ET.fromstring(RSS)
    kanal = ildiz.find("channel")
    print(f"=== 1. Lenta: {kanal.findtext('title')} ===")
    itemlar = kanal.findall("item")
    print(f"  jami maqolalar: {len(itemlar)}")

    maqolalar = [maqola_ol(item) for item in itemlar]

    print("\n=== 2. Muammoli maqolalar ===")
    for m in maqolalar:
        muammolar = []
        if m["sarlavha"] == "(sarlavhasiz)":
            muammolar.append("sarlavha yo'q")
        if m["sana"] is None:
            muammolar.append("sana noto'g'ri")
        if m["havola"] is None:
            muammolar.append("havola yo'q")
        if muammolar:
            print(f"  ⚠️ {m['sarlavha']}: {', '.join(muammolar)}")

    print("\n=== 3. Sana bo'yicha saralangan (yangi birinchi) ===")
    yaroqli = sorted((m for m in maqolalar if m["sana"]), key=lambda m: m["sana"], reverse=True)
    for m in yaroqli:
        teglar = ", ".join(m["teglar"]) or "—"
        print(f"  {m['sana']}  {m['sarlavha']:26} [{teglar}] muallif: {m['muallif']}")

    print("\n=== 4. Aralash kontent ===")
    kontentli = ildiz.find(".//content:encoded", NS)
    print(f"  content:encoded matni: {kontentli.text!r}")

    print("\n=== 5. Ichki hisobot (JSON) ===")
    hisobot = {"manba": kanal.findtext("title"), "jami": len(maqolalar), "maqolalar": yaroqli}
    print(json.dumps(hisobot, ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Lenta: Wisar Blog ===
  jami maqolalar: 3

=== 2. Muammoli maqolalar ===
  ⚠️ Sarlavhasiz qoralama: sana noto'g'ri, havola yo'q

=== 3. Sana bo'yicha saralangan (yangi birinchi) ===
  2026-09-17  Type hints amaliyoti       [python] muallif: Malika
  2026-09-15  Python 3.14 chiqdi         [python, yangilik] muallif: Aziz

=== 4. Aralash kontent ===
  content:encoded matni: 'Yangi versiyada <b>bepul-tred</b> rejimi bor.'

=== 5. Ichki hisobot (JSON) ===
{
  "manba": "Wisar Blog",
  "jami": 3,
  "maqolalar": [
    {
      "sarlavha": "Type hints amaliyoti",
      "havola": "https://wisar.uz/p/types",
      "sana": "2026-09-17",
      "muallif": "Malika",
      "teglar": [
        "python"
      ],
      "kontent_bormi": false
    },
    {
      "sarlavha": "Python 3.14 chiqdi",
      "havola": "https://wisar.uz/p/314",
      "sana": "2026-09-15",
      "muallif": "Aziz",
      "teglar": [
        "python",
        "yangilik"
      ],
      "kontent_bormi": true
    }
  ]
}

Nima ko'rsatdi: 2.2, 2.4, 2.6-bo'limlar.


5. To'g'ri va noto'g'ri tushunishlar

Noto'g'ri fikr To'g'risi
"XML — JSON ning eski ko'rinishi" Atribut/element farqi, aralash kontent, tartib bor
"find('teg') doim ishlaydi" Nom fazosi bo'lsa {uri}teg kerak
"<, & ni qo'lda almashtirish kerak" ElementTree avtomatik ekranlaydi
"Belgilar orasidagi matn faqat text" Element keyingi matn — tail
"stdlib XML hujumlardan himoyalangan" XXE dan — ha, entity kengayishidan — yo'q
"ET.parse katta faylni yaxshi o'qiydi" Butun daraxtni yuklaydi — iterparse kerak
"iterparse xotirani o'zi bo'shatadi" elem.clear() kerak
"[1] — ikkinchi element" XPath da 1 dan — birinchi

6. Keng tarqalgan xatolar va yechimlari

1. Nom fazosini unutish

python
ildiz.find("tranzaksiya")                          # ❌ None
ildiz.find("tranzaksiya", {"": "urn:iso:20022"})   # ✅

2. Ishonchsiz XML ni stdlib bilan

python
ET.fromstring(tashqi_xml)                           # ⚠️ billion laughs
import defusedxml.ElementTree as ET                 # ✅ ishonchsiz manba uchun

3. Katta faylni parse bilan

python
ET.parse("500mb.xml")                               # ❌ xotira
for _, e in ET.iterparse("500mb.xml", events=("end",)):   # ✅
    if e.tag == "yozuv": ...; e.clear()

4. tail ni yo'qotish

python
"".join(e.text for e in ildiz)                      # ❌ oraliq matn yo'qoladi
"".join(ildiz.itertext())                           # ✅

5. None ni tekshirmaslik

python
kitob.find("narx").text                             # ❌ AttributeError agar yo'q bo'lsa
kitob.findtext("narx", default="0")                 # ✅

6. Belgilarni qo'lda ekranlash

python
elem.text = matn.replace("<", "&lt;")               # ❌ ikki marta ekranlanadi
elem.text = matn                                    # ✅ avtomatik

7. Atribut turini son deb olish

python
narx = kitob.get("narx") + 1000                     # ❌ str + int
narx = int(kitob.get("narx", "0")) + 1000           # ✅

8. XPath indeksni 0 dan deb o'ylash

python
ildiz.find("kitob[0]")                              # ❌ SyntaxError yoki bo'sh
ildiz.find("kitob[1]")                              # ✅ birinchi

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 4.9-dars (o'tilgan): kodlashlar va XML deklaratsiyasi
  • 16.2-dars (o'tilgan): JSON — XML ga zamonaviy muqobil
  • 16.4-dars (o'tilgan): pickle — entity kabi "kod bo'lgan ma'lumot" xavfi
  • 16.6-dars: YAML va TOML — sozlama formatlari
  • 16.8-dars: katta fayllarni oqim bilan o'qish
  • 22-qism: SOAP va eski veb-xizmatlar
  • 26.3–26.4-darslar: web scraping — HTML/XML ni tahlil qilish

8. Eng yaxshi amaliyotlar

  1. Nom fazolarini namespaces= lug'at bilan boshqaring.

  2. Ishonchsiz XML — defusedxml, stdlib emas.

  3. Katta fayllar — iterparse + elem.clear().

  4. Belgilarni qo'lda ekranlamang.

  5. findtext(..., default=...) bilan yo'q maydonlarga bardosh bering.

  6. Aralash kontentda tail/itertext ni hisobga oling.

  7. Yozishda ET.indent va aniq encoding.

  8. Murakkab XPath yoki tez tahlil kerak bo'lsa — lxml.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
import xml.etree.ElementTree as ET
r = ET.fromstring("<a x='1'><b>M</b><c/>T</a>")
1.  print(r.tag, r.get("x"))
2.  print(len(r))
3.  print(r.findtext("b"))
4.  print(r.find("c").text)
5.  print(r[1].tail)
6.  print(ET.tostring(ET.fromstring("<x>a&amp;b</x>"), encoding="unicode"))
7.  e = ET.Element("t"); e.text = "a<b"; print(ET.tostring(e, encoding="unicode"))
8.  print(ET.fromstring("<n xmlns='u'><m/></n>").find("m"))
9.  print(ET.fromstring("<n xmlns='u'><m/></n>").find("{u}m").tag)
10. print(ET.fromstring("<a><b/><b/></a>").findall("b").__len__())
11. print([x.text for x in ET.fromstring("<a><b>1</b><b>2</b></a>").iterfind("b")])
12. try:
        ET.fromstring("<a><b></a>")
    except ET.ParseError as e:
        print(type(e).__name__)
Javoblar
  1. a 1
  2. 2
  3. M
  4. None
  5. T
  6. <x>a&amp;b</x>
  7. <t>a&lt;b</t>
  8. None
  9. {u}m
  10. 2
  11. ['1', '2']
  12. ParseError

Vazifa 2: Xatolarni tuzating

python
1.  def summa(xml_matn):
        r = ET.fromstring(xml_matn)
        return sum(k.find("narx").text for k in r.findall("kitob"))

2.  def ismlar(xml_fayl):
        r = ET.parse(xml_fayl).getroot()          # 300 MB fayl
        return [e.text for e in r.findall(".//ism")]

3.  def oqi(tashqi_xml):
        return ET.fromstring(tashqi_xml)          # foydalanuvchi yuborgan

4.  def topshiriq(r):                              # <hujjat xmlns="urn:x">
        return r.find("tranzaksiya").get("id")

5.  def yoz(sarlavha):
        e = ET.Element("item")
        e.text = "<b>" + sarlavha.replace("&", "&amp;") + "</b>"
        return ET.tostring(e, encoding="unicode")
Javoblar
python
1.  def summa(xml_matn):
        r = ET.fromstring(xml_matn)
        return sum(int(k.findtext("narx", "0")) for k in r.findall("kitob"))

2.  def ismlar(xml_fayl):
        natija = []
        for _, e in ET.iterparse(xml_fayl, events=("end",)):
            if e.tag == "ism":
                natija.append(e.text)
                e.clear()
        return natija

3.  import defusedxml.ElementTree as DET
    def oqi(tashqi_xml):
        return DET.fromstring(tashqi_xml)          # entity/DTD bloklanadi

4.  def topshiriq(r):
        NS = {"": "urn:x"}
        el = r.find("tranzaksiya", NS)
        return el.get("id") if el is not None else None

5.  def yoz(sarlavha):
        e = ET.Element("item")
        b = ET.SubElement(e, "b")
        b.text = sarlavha                          # ekranlashni ET qiladi
        return ET.tostring(e, encoding="unicode")

Vazifa 3: XML ↔ JSON konvertor

  1. XML → JSON: atributlarni @atr, matnni #text, takroriy elementlarni ro'yxat qiling
  2. JSON → XML: teskari; nom fazolarini saqlang
  3. Aralash kontent (text+tail) ni ham to'g'ri o'tkazing
  4. Aylanib qaytish testi: XML → JSON → XML semantik teng bo'lsin

Vazifa 4: Sitemap generatori va validatori

  1. <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> yarating (URL, lastmod, priority)
  2. 50 000 URL chegarasi va 50 MB hajm cheklovini tekshiring
  3. Mavjud sitemap ni o'qib, buzuq URL va sana formatlarini toping
  4. Katta sitemap ni iterparse bilan tekshiring

Vazifa 5: Xavfsiz XML yuklovchi

  1. xavfsiz_oqi(xml) — defusedxml bo'lsa undan, bo'lmasa DTD ni rad etuvchi parser bilan
  2. Entity kengayishini aniqlang: manba hajmi va natija hajmi nisbati chegarasi
  3. XXE urinishini jurnalga yozing (15.16)
  4. lxml ning resolve_entities=False varianti bilan solishtiring

Vazifa 6: .docx dan matn ajratish

  1. .docx — zip ichida word/document.xml (16.1 va zipfile)
  2. Nom fazoli <w:t> elementlaridan matnni ajrating
  3. Paragraf (<w:p>) larni qatorlarga bo'ling
  4. 100 MB hujjatda iterparse bilan xotirani o'lchang

Vazifa 7: O'ylash

XML "hamma narsani belgilash" g'oyasi bilan yaratildi va 2000-yillarda korporativ dunyoni egalladi (SOAP, XSD, XSLT, WS-*). Keyin JSON kelib, veb API larida uni deyarli butunlay siqib chiqardi. Nima uchun XML web da yutqazdi, lekin hujjatlar (Office, SVG), konfiguratsiya (Android) va korporativ integratsiyada (ISO 20022 to'lovlar) hamon yashaydi? XML ning qaysi kuchli tomonlari JSON da yo'q?

Javob

Qisqa javob: XML web API larida yutqazdi, chunki u ma'lumot uzatish uchun JSON dan og'irroq: teglar takrorlanadi, nom fazolari murakkab, brauzerda JSON.parse bepul ishlaydi. Lekin XML hujjat formati sifatida — matn, tuzilma va metama'lumot aralash bo'lgan joyda — JSON qila olmaydigan narsalarni qiladi: aralash kontent, sxema validatsiyasi (XSD), transformatsiya (XSLT), nom fazolari bilan modullilik. Shuning uchun u hujjat va tartibga solingan integratsiyada yashaydi.

1. Nega web da yutqazdi

Sabab Tafsilot
Og'irlik Ochiluvchi/yopiluvchi teglar — JSON dan kattaroq
Brauzer JSON.parse — tilning o'zida; XML uchun DOM API noqulay
Ma'lumot modeli JSON to'g'ridan-to'g'ri obyekt/massivga mos, XML — hujjatga
Murakkablik Nom fazolari, atribut/element farqi — ortiqcha yuk
Xavfsizlik XXE, entity portlashi — qo'shimcha ehtiyot

2. XML da bor, JSON da yo'q

Imkoniyat Tafsilot
Aralash kontent Matn va elementlar aralashishi (hujjatlar uchun tabiiy)
Atribut vs element Metama'lumot va kontent farqi
Nom fazolari Turli sxemalarni bir hujjatda aralashtirmasdan birlashtirish
XSD Kuchli, standart sxema validatsiyasi
XSLT XML ni boshqa formatga deklarativ o'zgartirish
Izohlar, ishlov ko'rsatmalari Hujjat metama'lumoti

3. Nega hujjat va integratsiyada yashaydi

Soha Sabab
Office (.docx, .xlsx) Aralash kontent, murakkab tuzilma, uzoq muddatli standart
SVG Grafika — hujjat tabiati
Android tartib Atribut/element, vositalar ekotizimi
ISO 20022 (to'lovlar) Qat'iy XSD validatsiya, banklararo kelishuv
SOAP (eski tizimlar) WS-* standartlari, inertsiya

4. Muhandislik saboqlari

  1. Format vazifaga mos bo'lishi kerak: ma'lumot uzatish — JSON, hujjat — XML
  2. XML ning validatsiya va transformatsiya kuchi — qat'iy integratsiyada qimmatli
  3. Murakkablik narxi bor: nom fazolari, xavfsizlik — ehtiyot talab qiladi
  4. Yangi loyihada API — JSON; mavjud XML integratsiyasi — to'g'ri vositalar bilan (sxema, defusedxml, iterparse)

5. Xulosa

  1. XML web da og'irligi va JSON ning soddaligi tufayli yutqazdi
  2. Aralash kontent, XSD, XSLT, nom fazolari — JSON da yo'q kuchlar
  3. Hujjat, grafika, qat'iy integratsiyada XML yashaydi
  4. To'g'ri vosita tanlash — muhandis mahorati

Nimani mustahkamlaydi: 2.2–2.8-bo'limlar.


Xulosa

Bu darsda XML ni ElementTree bilan o'qish, yozish va uning xavflarini o'rgandik.

Eng muhim uch fikr:

  1. ElementTree — o'qish, navigatsiya va qurish. fromstring/parse bilan o'qiladi, find/findall/findtext va XPath qism to'plami bilan navigatsiya qilinadi, Element/SubElement/tostring bilan quriladi. <, & kabi belgilar avtomatik ekranlanadi — qo'lda almashtirmang. Aralash kontentda element keyingi matn tail da bo'ladi; butun matn uchun itertext.

  2. Nom fazolari — eng ko'p adashtiradigan joy. xmlns bo'lsa teg aslida {uri}teg bo'ladi va oddiy find("teg") None qaytaradi. Yechim — nom fazolarini namespaces= lug'atga olish; yozishda register_namespace. Bank, to'lov va boshqa qat'iy integratsiyalarda bu doimiy uchraydi.

  3. XML xavfsizligi va katta fayllar. Python stdlib XXE (tashqi entity, fayl o'qish) dan sukut bo'yicha himoyalangan, lekin entity kengayishidan ("billion laughs") emas — ishonchsiz XML uchun defusedxml. Katta fayllarni ET.parse butun daraxtni xotiraga yuklaydi; yagona to'g'ri yo'l — iterparse va har yozuvdan keyin elem.clear().

Keyingi darsda odam yozadigan sozlama formatlarini — YAML va TOML ni o'rganamiz: nega ular JSON dan qulay, YAML ning mashhur tuzoqlari (yes/no, norway muammosi, safe_load) va nega Python pyproject.toml uchun TOML ni tanladi.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
16.5-dars: XML — IlmHamroh