Geonode logo
Geonode Team

Geonode Team

Güncellenme: 7 Ekim 2026

Yayınlanma: 2 Eylül 2026

JavaScript'te XML Nasıl Ayrıştırılır?

Tarayıcılarda yerleşik bir XML ayrıştırıcısı bulunur. Node.js’te ise yoktur. Bu tek asimetri, bu konuyla ilgili kafa karışıklığının büyük bir kısmını açıklıyor. Tarayıcılard`DOMParser`, XML'i herhangi bir bağımlılık olmadan işler ve bilmeniz gereken bir tuhaflığı vardır: hatalı biçimlendirilmiş girdilerde hata atmaz. Node'da ise bir kütüphane seçersiniz ve bu seçim, sonraki tüm kod yazımınızı etkiler. Bu kılavuz her ikisini de ele alır; ayrıca ad alanları, XPath ve kullanıcıların sıkça karşılaştığı güvenlik sorununu da kapsar.

Bunu yazmamızın nedeni şudur: Biz Geonode olarak, veri toplayan kişilere proxy satıyoruz ve bu verilerin büyük bir kısmı XML formatında geliyor — site haritaları, RSS ve Atom beslemeleri, SOAP yanıtları, ürün katalogları. Açıkçası, ayrıştırma hatası neredeyse hiçbir zaman bir ağ sorunu değildir. XML ayrıştırıcınız hata veriyorsa, herhangi bir kod değişikliği yapmadan önce aldığınız verinin ilk 200 karakterini ekrana yazdırın. On vakadan dokuzunda bu bir HTML hata sayfasıdır ve ayrıştırıcı, size XML gönderilmediğini doğru bir şekilde bildiriyor demektir.

Tarayıcıda: DOMParser

Yerleşik, bağımlılık içermez.

const parser = new DOMParser();
const doc = parser.parseFromString(xmlString, "application/xml");

const titles = doc.querySelectorAll("item > title");
titles.forEach(t => console.log(t.textContent));

MDN belgeleri, kabul edilen MIME türlerini şu şekilde listeler: text/html

, text/xml

, application/xml

, application/xhtml+xml

ve image/svg+xml

. Bu, "verilen mimeType

ile eşleşen bir contentType

özelliğine sahip" bir Document

döndürür; bu, ne talep ettiğinize bağlı olarak bir HTMLDocument

veya bir XMLDocument

olabilir.

XML için application/xml

kullanın. text/html

parametresini geçmek HTML ayrıştırıcısını çalıştırır; bu ayrıştırıcı, belgenizi sessizce değiştirecek şekilde esnektir — XML’in büyük/küçük harf duyarlılığını dikkate almaz ve XML’in yasakladığı öğeleri de sorunsuzca kabul eder.

Ayrıştırma işlemi tamamlandığında bir DOM elde edersiniz. DOM gezintisi hakkında bildiğiniz her şey burada da geçerlidir: querySelector

, querySelectorAll

, getElementsByTagName

, children

, textContent

.

Hata Tuzağı: İstisna Oluşturmaz

İlk seferde herkesin tuzağa düştüğü davranış.

DOMParser adresine hatalı biçimlendirilmiş bir XML dosyası gönderirseniz, bir istisna oluşturulmaz. MDN bu konuda açıkça belirtir: “Döndürülen XMLDocument, ayrıştırma hatasını açıklayan bir <parsererror> düğümü içerecektir” ve hata “tarayıcının JavaScript konsoluna da bildirilebilir”.

Bu nedenle şunu kontrol etmelisiniz:

const doc = parser.parseFromString(xmlString, "application/xml");
const errorNode = doc.querySelector("parsererror");
if (errorNode) {
  throw new Error(`XML parse failed: ${errorNode.textContent}`);
}

Bu kontrol yapılmazsa, hatalı biçimlendirilmiş bir belge, verilerinizin olması gereken yerde bir hata mesajı içeren bir Document nesnesi üretir. Ardından yaptığınız querySelectorAll çağrısı hiçbir şey döndürmez ve bu durum, ayrıştırma hatasından ziyade bir seçici sorunu gibi görünür.

Bunu bir kez sarın:

function parseXml(text) {
  const doc = new DOMParser().parseFromString(text, "application/xml");
  const err = doc.querySelector("parsererror");
  if (err) {
    throw new Error(
      `XML parse failed: ${err.textContent.trim()}. ` +
      `First 200 chars: ${text.slice(0, 200)}`
    );
  }
  return doc;
}

text.slice(0, 200), zaman kazandıran kısımdır. Bir ayrıştırma hatası, girdinin geçersiz olduğunu gösterir; ilk 200 karakter ise bunun bir HTML hata sayfası olduğunu gösterir.

Node'da: Kütüphane Seçimi

Node'da yerleşik bir XML ayrıştırıcısı bulunmadığından, bu bir bağımlılık kararıdır. Haftalık indirme rakamları, kütüphanenin ne kadar yaygın olarak kullanıldığına dair genel bir fikir verir — bu rakamlar, Eylül 2026'da kontrol edilen npm kayıt defterinden alınmıştır.

KütüphaneHaftalık indirmelerStil
sax

| ~88,9 milyon | Akış, olay tabanlı | | fast-xml-parser

| ~85,0 milyon | XML'den düz JavaScript nesnelerine | | @xmldom/xmldom

| ~48,7 milyon | Node için DOM uygulaması | | xml2js

| ~44,5M | XML'den nesnelere, geri arama ve promise API'leri | | xpath

| ~12,2M | XPath sorguları, xmldom ile birlikte kullanılır |

**fast-xml-parser

** çoğu iş için pratik bir varsayılan seçenektir. XML'i sıradan JavaScript nesnelerine dönüştürür; bu da DOM yöntemleri yerine nokta notasyonu ile gezinebileceğiniz anlamına gelir:

import { XMLParser } from "fast-xml-parser";

const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: "@" });
const obj = parser.parse(xmlString);
console.log(obj.rss.channel.item[0].title);

Anlamanız gereken bir dezavantaj: nesne dönüştürme, belirli bir açıdan kayıplı bir işlemdir. Bir kez görünen bir öğe bir nesne haline gelir; aynı öğe iki kez görünürse bir dizi haline gelir. Dolayısıyla, channel.item

üç öğeli bir besleme için bir dizi, tek öğeli bir besleme için ise bir nesne olur — ve bir dizi olduğunu varsayan kod, tek öğeli durumda hata verir. Çoğu kütüphane, adlandırılmış öğeler için her zaman dizi üretme seçeneği sunar; yineleme yapacağınız her şey için bu seçeneği etkinleştirmek, sorun yaşamadan önce yapmanız gereken bir işlemdir.

**@xmldom/xmldom

**, Node'da gerçek bir DOM sağlar; bu, aynı kodun her iki ortamda da çalışmasını istiyorsanız veya XPath'e ihtiyacınız varsa önemlidir. Bunu xpath

paketiyle birlikte kullanın:

import { DOMParser } from "@xmldom/xmldom";
import xpath from "xpath";

const doc = new DOMParser().parseFromString(xmlString, "text/xml");
const titles = xpath.select("//item/title/text()", doc);

**sax

**, okudukça olaylar üreten bir akış ayrıştırıcısıdır. Bu, DOM yaklaşımının kesinlikle uygun olmadığı, bellekte tutulamayacak kadar büyük belgeler — birkaç gigabaytlık bir site haritası dizini, toplu katalog dışa aktarımı — için ideal çözümdür.

**xml2js

** uzun süredir piyasada olan ve yaygın olarak kullanılan bir araçtır. API'si biraz eski olsa da tamamen işlevseldir ve onu kullanan çok sayıda mevcut kod bulunmaktadır.

Ad Alanları: Gerçek Belgeleri Bozan Unsur

Çalışan bir seçicinin aniden hiçbir şey bulamamasının en yaygın nedeni.

Birçok gerçek XML biçimi ad alanlarını bildirir:

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url><loc>https://example.com/</loc></url>
</urlset>

xmlns

, her öğeyi varsayılan bir ad alanına yerleştirir. Ad alanını destekleyen bir ayrıştırıcıda, <loc>

sadece loc

değildir — bu, sitemaps ad alanındaki loc

'dir ve basit bir getElementsByTagName("loc")

hiçbir şey bulamayabilir.

Bunu ele almanın, doğruluk derecesine göre artan sırayla üç yolu vardır.

Ad alanı farkındalığına sahip yöntemleri kullanın:

const NS = "http://www.sitemaps.org/schemas/sitemap/0.9";
const locs = doc.getElementsByTagNameNS(NS, "loc");

Hangisi olduğu önemli değilse, joker karakterli ad alanı kullanın:

const locs = doc.getElementsByTagNameNS("*", "loc");

Kütüphanenizi ad alanlarını yok sayacak şekilde yapılandırın. Çoğu nesne eşleme kütüphanesi, ad alanı öneklerini kaldırma seçeneğine sahiptir; bu da düz loc

anahtarları üretir. Bu, kullanışlıdır ve tesadüfen aynı yerel adı paylaşan iki gerçekten farklı öğeyi sessizce birleştirir — bu, bir site haritası için kabul edilebilir, ancak farklı sözcük dağarcıklarını karıştıran bir belge için tehlikelidir.

querySelector

'in burada getElementsByTagNameNS

'dan farklı davrandığını unutmayın: CSS seçicilerinin kendi ad alanı sözdizimi vardır; bu sözdizimi kullanışsızdır ve nadiren kullanılır; bu nedenle, ad alanı içeren XML için NS

yöntemleri veya XPath daha güvenilirdir.

JavaScript’te XPath

Tarayıcılarda document.evaluate adresi üzerinden, Node’da ise xmldom adresindeki xpath paketi aracılığıyla kullanılabilir. .

const result = doc.evaluate(
  "//item/title/text()",
  doc,
  null,
  XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
  null
);
for (let i = 0; i < result.snapshotLength; i++) {
  console.log(result.snapshotItem(i).nodeValue);
}

API o kadar ayrıntılı ki çoğu kişi onu bir kez kullanıp sonra unutur. Bunun zahmetine değmesini sağlayan şey ise, XPath’in CSS seçicilerinin ifade edemediği şeyleri ifade edebilmesidir — metin içeriğine göre eşleştirme, üst öğelere geçiş ve kardeş öğelere göre konumsal mantık.

İki kısıtlama vardır. Tarayıcılar XPath 1.0'ı uygular; dolayısıyla matches(), lower-case() ve ends-with() kullanılamaz. Ayrıca ad alanları, önekleri ad alanı URI'lerine eşleyen bir çözümleyici işlevi (üçüncü argüman) gerektirir. null biçiminin kullanılması yalnızca ad alanı içermeyen belgeler için geçerlidir; bu da çoğu gerçek beslemeyi kapsam dışı bırakır.

Tarayıcıda ad alanı içeren belgeler için:

const resolver = prefix => ({ sm: "http://www.sitemaps.org/schemas/sitemap/0.9" }[prefix] || null);
const result = doc.evaluate("//sm:loc/text()", doc, resolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);

XPath 1.0’da varsayılan ad alanı kavramı bulunmadığından, belgenin kullandığı önek ne olursa olsun öneki (burada sm) kendiniz belirlemeniz gerektiğini unutmayın.

XML’i JSON’a Dönüştürme ve Kaybedilenler

Aslında insanların en çok istediği şey budur; ancak bu dönüştürme işleminin kayıpsız olmadığını anlamakta fayda var.

XML ve JSON'un farklı veri modelleri vardır. XML'de öznitelikler, öğeler, metin düğümleri, yorumlar, işleme talimatları, ad alanları ve sıralama bulunur. JSON'da ise nesneler, diziler, dizeler, sayılar, boole değerleri ve null vardır. Dört öğe bu dönüşüm sürecinden kayıpsız çıkamaz.

Özellikler ve alt öğeler. <item id="1"><name>x</name></item> öğesinde bir özellik ve bir alt öğe vardır; JSON'da ise ikisi arasında bir ayrım yoktur. Kütüphaneler bu durumu, özellik anahtarlarının başına önek ekleyerek (genellikle @ veya $) halleder; bu önekleri siz yapılandırırsınız ve daha sonra hatırlamanız gerekir:

const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: "@" });
// { item: { "@id": "1", name: "x" } }

Tekrarlanan öğeler tutarsız bir şekilde dizilere dönüşür. Yukarıda ele alınmış olsa da, bu alandaki en yaygın hata olduğu için tekrarlamakta fayda var: bir kez tekrarlanması bir nesne, iki kez tekrarlanması ise bir dizi verir. İterasyon yapmayı planladığınız her öğe için kütüphanenin "her zaman dizi" seçeneğini ayarlayın.

Karışık içeriğin net bir temsil biçimi yoktur. <p>Hello <b>world</b>!</p>, metin ve öğeleri birbirine karıştırır. Bir nesneye dönüştürüldüğünde, metin parçalarının ve bunların alt öğeye göre konumlarının temsil edilmesi zordur; çoğu kütüphane metni birleştirir ya da bir kısmını atar. XML'iniz düz metin işaretlemesi içeriyorsa, nesneye dönüştürme yanlış bir yaklaşımdır — DOM'u koruyun.

Sıra garanti edilmez. JSON nesne anahtarlarının veri modelinde tanımlanmış bir sırası yoktur; bu nedenle, öğe sırasının anlam taşıdığı bir belge bu bilgiyi kaybeder. Diziler sırayı korur; farklı isimlere sahip kardeş öğeler ise korumaz.

Aksi belirtilmedikçe her şey bir dize haline gelir. XML'de türler yoktur; bu nedenle <price>42.50</price> bir metindir. Çoğu kütüphane sayısal zorlama özelliği sunar; bu kullanışlıdır ve başındaki sıfırları içeren ürün kodunu bir sayıya, sürüm dizesini ise bir float sayısına dönüştürür. Miktar değil de tanımlayıcı niteliğinde olan her şey için zorlama özelliğini kapatın.

Pratik rehber: Nesne dönüştürme, öğelerin kayıtlar ve alanlar olduğu veri biçimindeki XML’ler — beslemeler, kataloglar, yapılandırma, API yanıtları — için uygundur. İşaretlemenin metin içine gömülü olduğu ve yapının anlam taşıdığı belge biçimindeki XML’ler için bir DOM kullanın.

Güvenlik: XXE ve Enjeksiyon

İkisi de gerçek olan iki farklı risk.

XML Dış Varlık İşleme. XML, yerel dosyalar ve ağ URL’leri dahil olmak üzere dış kaynaklara atıfta bulunan varlıkları tanımlayabilir. Bunları çözümleyen bir ayrıştırıcı, sunucudan dosya okumaya veya saldırgan adına isteklerde bulunmaya zorlanabilir. Bu, klasik ve hâlâ yaygın bir güvenlik açığı türüdür.

Bunu önlemek için, kullandığınız ayrıştırıcıda harici varlık ve DTD işlemeyi devre dışı bırakmanız gerekir. DOMParser, harici varlıkların çözümlenmesini desteklemez; bu nedenle tarayıcılar varsayılan olarak güvenlidir. Node kütüphaneleri farklılık gösterir; bu nedenle varsayımda bulunmak yerine kontrol etmek önemlidir — Node'da güvenilir olmayan bir kaynaktan XML ayrıştırıyorsanız, yayınlamadan önce ayrıştırıcınızın varlık işleme özelliğini doğrulayın.

DOM'a yeniden eklenirken enjeksiyon. MDN, parseFromString adresinin "bir 'enjeksiyon havuzu' olduğunu ve girişin bir saldırgana ait olması durumunda XSS saldırıları için potansiyel bir vektör oluşturduğunu" belirtmektedir. Buradaki nüans önemlidir: text/html adresinde belirtildiği gibi, "<script> öğeleri çalıştırılamaz olarak işaretlenir ve olay işleyicileri çağrılmaz" — ancak "ayrıştırılan belge daha sonra görünür DOM'a enjekte edilirse komut dosyaları çalışacaktır".

Dolayısıyla ayrıştırma güvenlidir; sonucun eklenmesi ise güvenli değildir. MDN’nin önerileri şunlardır: dizeler yerine TrustedHTML nesnelerini aktarın, CSP require-trusted-types-for yönergesi aracılığıyla güvenilir türleri zorunlu kılın ve TrustedTypePolicy aracılığıyla DOMPurify gibi bir kütüphaneyle temizleme işlemi uygulayın.

Basit kural şudur: ayrıştırılmış, güvenilir olmayan işaretlemeyi temizlemeden asla canlı DOM’a eklemeyin ve yalnızca metne ihtiyacınız olduğunda innerHTML yerine textContent kullanın.

Pratik Örnekler

RSS veya Atom beslemesini ayrıştırma:

const doc = parseXml(await res.text());
const items = [...doc.getElementsByTagNameNS("*", "item")].map(item => ({
  title: item.getElementsByTagNameNS("*", "title")[0]?.textContent?.trim(),
  link:  item.getElementsByTagNameNS("*", "link")[0]?.textContent?.trim(),
  date:  item.getElementsByTagNameNS("*", "pubDate")[0]?.textContent?.trim(),
}));

Joker ad alanı, dallanmaya gerek kalmadan hem RSS hem de Atom’u işler; isteğe bağlı zincirleme ise eksik alanları olan beslemeleri işler — ki bunların çoğu böyledir.

Dizin dosyaları dahil olmak üzere bir site haritasını ayrıştırma:

const doc = parseXml(xml);
const isIndex = doc.documentElement.localName === "sitemapindex";
const locs = [...doc.getElementsByTagNameNS("*", "loc")].map(n => n.textContent.trim());
// if isIndex, these are sitemap URLs to fetch; otherwise they are page URLs

Her ikisi de <loc>

öğelerini içerdiğinden ve yalnızca sarmalayıcı farklı olduğundan, belge öğesindeki localName

değerini kontrol etmek bu ikisini ayırt etmenin güvenilir yoludur.

Büyük bir belgeyi işleme — DOM oluşturmak yerine akış tabanlı bir ayrıştırıcı kullanın:

import sax from "sax";
const stream = sax.createStream(true, { trim: true });
let current = null;
stream.on("opentag", node => { if (node.name === "loc") current = ""; });
stream.on("text", t => { if (current !== null) current += t; });
stream.on("closetag", name => { if (name === "loc") { emit(current); current = null; } });

Küçük bir durum makinesi yazma bedeli karşılığında, belge boyutundan bağımsız olarak sabit bellek kullanımı sağlanır.

Sık Sorulan Sorular

JavaScript'te XML'i nasıl ayrıştırabilirim?

Tarayıcıda, yerleşik DOMParser işlevini kullanın: new DOMParser().parseFromString(xml, "application/xml") komutu, DOM yöntemleriyle sorgulayabileceğiniz bir Document döndürür. Node'da yerleşik bir ayrıştırıcı bulunmadığından, bir tane yüklemeniz gerekir — nesne dönüştürme için fast-xml-parser, gerçek DOM için @xmldom/xmldom.

DOMParser, geçersiz XML'de neden istisna atmaz?

Tasarım gereği böyledir. Bir istisna yerine, döndürülen belge, hatayı açıklayan bir <parsererror> düğümü içerir. Bunu doc.querySelector("parsererror") ile açıkça kontrol etmeniz gerekir; aksi takdirde, biçim hatası olan bir belge sessizce boş sorgu sonuçları üretecektir.

Node.js'de yerleşik bir XML ayrıştırıcısı var mı?

Hayır. JSON'dan farklı olarak, XML için bir bağımlılık gereklidir. Yaygın olarak kullanılan seçenekler arasında nesnelere dönüştürme için fast-xml-parser ve xml2js, DOM uygulaması için @xmldom/xmldom ve çok büyük belgeleri akış olarak işlemek için sax bulunur.

XML seçicim neden hiçbir şey bulamıyor?

Genellikle isim alanları yüzünden. xmlns şeklinde bir isim alanı beyan eden bir belge, her öğeyi o isim alanına yerleştirir ve basit bir getElementsByTagName ifadesi eşleşmeyebilir. İsim alanı URI’siyle birlikte getElementsByTagNameNS kullanın, joker karakter olarak "*" kullanın ya da kütüphanenizi isim alanlarını yok sayacak şekilde yapılandırın.

JavaScript’te XML ile XPath’i nasıl kullanırım?

Tarayıcılarda, XPathResult türünde bir document.evaluate kullanın — bir kez sarmalamaya yetecek kadar ayrıntılı olmalıdır. Node'da ise xpath paketi ile @xmldom/xmldom birlikte kullanılır. Tarayıcıların yalnızca XPath 1.0'ı uyguladığını ve ad alanı içeren belgelerin, önekleri URI'lere eşleyen bir çözümleyici işlevine ihtiyaç duyduğunu unutmayın.

JavaScript'te XML'i ayrıştırmak bir güvenlik riski oluşturur mu?

İki risk vardır. XML Dış Varlık işleme, bir ayrıştırıcının yerel dosyaları okumasına veya istekler göndermesine neden olabilir — tarayıcıdaki DOMParser dış varlıkları çözümlemez, ancak Node kütüphaneleri farklılık gösterir ve kontrol edilmelidir. Ayrıca, ayrıştırılmış ve güvenilir olmayan işaretlemeyi canlı DOM'a eklemek komut dosyalarını çalıştırabilir, bu nedenle eklemeden önce temizleyin.

Çok büyük bir XML dosyasını nasıl ayrıştırabilirim?

sax gibi, bellekte bir belge oluşturmak yerine okudukça olaylar üreten bir akış ayrıştırıcısı kullanın. Bu, bulunduğunuz yeri takip etmek için küçük bir durum makinesi yazma bedeli karşılığında, sabit bellek içinde her boyuttaki dosyayı işler.

Ayrıştırdığım XML bazen neden bir dizi, bazen de bir nesne veriyor?

Çünkü nesne eşleme kütüphaneleri, yalnızca bir öğe tekrarlandığında dizi üretir. Üç öğe içeren bir besleme size bir dizi verir; aynı besleme tek bir öğe içerdiğinde ise bir nesne verir. Çoğu kütüphanede, adlandırılmış öğeler için her zaman dizi üretme seçeneği bulunur — yineleme yaptığınız her şey için bu seçeneği etkinleştirin.

Sonuç

Bunun büyük bir kısmı çalışma ortamına bağlıdır. Tarayıcıda DOMParser adresi vardır ve herhangi bir bağımlılık yoktur; Node’da ise bir kütüphane seçersiniz ve bu seçim, sonraki tüm kod yazımınızı şekillendirir.

İnsanların zaman kaybetmesinin en büyük nedeni iki davranıştandır. DOMParser, istisna yerine parsererror düğümüyle hataları bildirir; bu nedenle, biçim hatası olan bir belge, seçici sorunu gibi görünen boş sonuçlar verir — bu düğümü kontrol edin ve girdinin ilk 200 karakterini günlüğe kaydedin, çünkü bu genellikle bir HTML hata sayfasıdır. Ayrıca, ad alanları, tam da en çok ayrıştırmak istediğiniz belgelerde (site haritaları, beslemeler ve SOAP yanıtları) düz etiket adı aramalarını sessizce bozar; çünkü bunların hepsi ad alanlarını bildirir.

Bunun ötesinde, aracı boyutuna göre seçin. Sıradan belgeler için nesne eşlemesi, XPath'e veya paylaşılan tarayıcı ve sunucu koduna ihtiyacınız olduğunda gerçek bir DOM ve dosya çok büyük olduğu için bir kerede tutulamadığında akış ayrıştırıcısı kullanın. Kaynak güvenilir değilse, yayınlamadan önce Node ayrıştırıcınızın harici varlık işleme özelliğini kontrol edin — bu, yirmi yıldır bir güvenlik açığı sınıfı olmuştur ve hâlâ da öyledir.