Dokunduğunuz her SOAP servisi, tükettiğiniz her RSS beslemesi, değiştirdiğiniz her SVG — hepsi XML'dir. JavaScript'in tarayıcıda iki yerleşik ayrıştırma yolu ve Node.js için sağlam bir npm kütüphanesi vardır. Zor kısım ayrıştırmanın kendisi değildir; asıl sorun ortaya çıkan DOM'da gezinmek, ad alanlarını ele almak ve ilk seferinde herkesi yakalayan tuhaflıklara takılmamaktır. Gerçek desenleri birlikte inceleyelim.

DOMParser — Tarayıcıda XML Ayrıştırma

Tarayıcının yerleşik DOMParser API'si bir XML dizesini DOM belgesine dönüştürür. Ayrıştırıcının katı XML kurallarını uygulaması için ('text/html' değil) 'application/xml' MIME türünü kullanın:

js
const xmlString = `<?xml version="1.0" encoding="UTF-8"?>
<library>
  <book isbn="978-0-13-110362-7">
    <title>The C Programming Language</title>
    <authors>
      <author>Brian W. Kernighan</author>
      <author>Dennis M. Ritchie</author>
    </authors>
    <year>1988</year>
    <price currency="USD">45.99</price>
  </book>
  <book isbn="978-0-201-63361-0">
    <title>The Pragmatic Programmer</title>
    <authors>
      <author>Andrew Hunt</author>
      <author>David Thomas</author>
    </authors>
    <year>1999</year>
    <price currency="USD">52.00</price>
  </book>
</library>`;

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

// Her zaman önce ayrıştırma hatalarını kontrol edin
const parseError = doc.querySelector('parsererror');
if (parseError) {
  throw new Error('XML parse failed: ' + parseError.textContent);
}

console.log(doc.documentElement.tagName); // library
Her zaman parsererror'u kontrol edin. İstisna fırlatan JSON.parse()'den farklı olarak, DOMParser ayrıştırma başarısız olduğunda bir <parsererror> elementi içeren belge döndürür — istisna fırlatmaz. Hata kontrolünü atlarsanız, hatalı biçimlendirilmiş belge üzerinde sessizce çalışırsınız ve ileride kafa karıştırıcı sonuçlar elde edersiniz.

DOM'da Gezinme — getElementsByTagName ve querySelector

Ayrıştırılmış bir belgeniz olduğunda, element bulmak için iki ana API bulunur. İkisi de çalışır ama farklı güçleri vardır:

js
// getElementsByTagName — canlı bir HTMLCollection döndürür
const books = doc.getElementsByTagName('book');
console.log(books.length); // 2

// querySelector / querySelectorAll — CSS seçici sözdizimi, NodeList döndürür
const firstTitle = doc.querySelector('title').textContent;
console.log(firstTitle); // The C Programming Language

// Tüm başlıkları al
const titles = [...doc.querySelectorAll('title')].map(el => el.textContent);
console.log(titles);
// ['The C Programming Language', 'The Pragmatic Programmer']

// Nitelikleri okuma
const firstBook = doc.querySelector('book');
const isbn = firstBook.getAttribute('isbn');
console.log(isbn); // 978-0-13-110362-7

// Fiyattan currency niteliğini okuma
const priceEl = firstBook.querySelector('price');
console.log(priceEl.textContent);           // 45.99
console.log(priceEl.getAttribute('currency')); // USD

Hedefli aramalar için querySelector'ı tercih ederim — CSS seçici sözdizimi tanıdık ve özdür. Belirli bir etiketli tüm elementlere ihtiyacınız olduğunda ve canlı bir koleksiyon istediğinizde getElementsByTagName'i kullanın (pratikte spread ile NodeList genellikle daha temizdir).

Yapılandırılmış Veri Çıkarma — Pratik Bir Desen

Bir XML belgesini temiz bir JavaScript nesne dizisine nasıl eşleyeceğiniz aşağıda açıklanmıştır — gerçek bir XML API yanıtı tüketirken kullanacağınız desen:

js
function parseLibraryXml(xmlString) {
  const parser = new DOMParser();
  const doc = parser.parseFromString(xmlString, 'application/xml');

  if (doc.querySelector('parsererror')) {
    throw new Error('Invalid XML');
  }

  return [...doc.querySelectorAll('book')].map(book => ({
    isbn: book.getAttribute('isbn'),
    title: book.querySelector('title').textContent.trim(),
    authors: [...book.querySelectorAll('author')].map(a => a.textContent.trim()),
    year: parseInt(book.querySelector('year').textContent, 10),
    price: {
      amount: parseFloat(book.querySelector('price').textContent),
      currency: book.querySelector('price').getAttribute('currency')
    }
  }));
}

const books = parseLibraryXml(xmlString);
console.log(books[0].title);          // The C Programming Language
console.log(books[0].authors);        // ['Brian W. Kernighan', 'Dennis M. Ritchie']
console.log(books[0].price.amount);   // 45.99

Ad Alanlı XML ile Çalışma

Ad alanları, çoğu geliştiricinin takıldığı yerdir. SOAP yanıtları, Atom beslemeleri ve SVG'nin hepsi XML ad alanları kullanır — ve SOAP belgesinde naif bir querySelector('body'), element aslında soap:Body olduğu için null döndürür. Bunu doğru şekilde ele alma yöntemi:

js
const soapResponse = `<?xml version="1.0"?>
<soap:Envelope
  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:m="http://www.example.com/orders">
  <soap:Header/>
  <soap:Body>
    <m:GetOrderResponse>
      <m:OrderId>ORD-5521</m:OrderId>
      <m:Status>Shipped</m:Status>
      <m:Total currency="EUR">289.50</m:Total>
    </m:GetOrderResponse>
  </soap:Body>
</soap:Envelope>`;

const parser = new DOMParser();
const doc = parser.parseFromString(soapResponse, 'application/xml');

// Seçenek 1: getElementsByTagNameNS — açık ad alanı URI'si
const SOAP_NS = 'http://schemas.xmlsoap.org/soap/envelope/';
const ORDER_NS = 'http://www.example.com/orders';

const body = doc.getElementsByTagNameNS(SOAP_NS, 'Body')[0];
const orderId = doc.getElementsByTagNameNS(ORDER_NS, 'OrderId')[0].textContent;
const status = doc.getElementsByTagNameNS(ORDER_NS, 'Status')[0].textContent;

console.log(orderId); // ORD-5521
console.log(status);  // Shipped

// Seçenek 2: Ad alanı çözücüyle XPath (daha esnek)
function nsResolver(prefix) {
  const namespaces = {
    soap: 'http://schemas.xmlsoap.org/soap/envelope/',
    m: 'http://www.example.com/orders'
  };
  return namespaces[prefix] || null;
}

const xpathResult = doc.evaluate(
  '//m:OrderId',
  doc,
  nsResolver,
  XPathResult.STRING_TYPE,
  null
);
console.log(xpathResult.stringValue); // ORD-5521

evaluate() ile XPath Sorguları

XPath, XML belgeleri için bir sorgu dilidir. Tarayıcı bunu document.evaluate() aracılığıyla sunar. XML için CSS seçicilerinden daha güçlüdür — nitelik değerine, konuma, metin içeriğine ve ataya göre sorgulama yapabilirsiniz. Tam ifade sözdizimi için MDN XPath belgelerine bakın:

js
// Daha önce kullandığımız kütüphane XML belgesini kullanarak
function xpath(doc, expression, contextNode = doc) {
  const result = doc.evaluate(
    expression,
    contextNode,
    null,  // ad alanı çözücü — ad alansız XML için null
    XPathResult.ANY_TYPE,
    null
  );
  return result;
}

// Tüm kitap başlıklarını al
const titlesResult = xpath(doc, '//book/title');
const titles = [];
let node;
while ((node = titlesResult.iterateNext())) {
  titles.push(node.textContent);
}
console.log(titles);
// ['The C Programming Language', 'The Pragmatic Programmer']

// Belirli ISBN'li kitabı al
const bookResult = doc.evaluate(
  '//book[@isbn="978-0-13-110362-7"]/title',
  doc, null,
  XPathResult.STRING_TYPE,
  null
);
console.log(bookResult.stringValue); // The C Programming Language

// 50 dolardan pahalı kitapları al
const expensiveResult = xpath(doc, '//book[price > 50]/title');
let expensiveNode;
while ((expensiveNode = expensiveResult.iterateNext())) {
  console.log(expensiveNode.textContent); // The Pragmatic Programmer
}

Node.js — fast-xml-parser (En İyi Seçenek)

Node.js'de DOMParser yoktur. İki seçeneğiniz var: yerleşik node:stream tabanlı SAX yaklaşımını kullanın (zahmetli) ya da fast-xml-parser kullanın (çoğu kullanım senaryosu için doğru seçim). Hızlı, bağımlılıksız ve düz JavaScript nesneleri döndürür:

bash
npm install fast-xml-parser
js
import { XMLParser } from 'fast-xml-parser';

const xmlString = `<?xml version="1.0"?>
<library>
  <book isbn="978-0-13-110362-7">
    <title>The C Programming Language</title>
    <year>1988</year>
    <price currency="USD">45.99</price>
  </book>
  <book isbn="978-0-201-63361-0">
    <title>The Pragmatic Programmer</title>
    <year>1999</year>
    <price currency="USD">52.00</price>
  </book>
</library>`;

const parser = new XMLParser({
  ignoreAttributes: false,     // XML niteliklerini dahil et
  attributeNamePrefix: '@_',   // nitelikleri elementlerden ayırmak için önek ekle
  isArray: (tagName) => tagName === 'book'  // <book>'u her zaman dizi olarak işle
});

const result = parser.parse(xmlString);
const books = result.library.book;

books.forEach(book => {
  console.log(book.title);       // The C Programming Language
  console.log(book['@_isbn']);   // 978-0-13-110362-7
  console.log(book.price['#text']);       // 45.99
  console.log(book.price['@_currency']); // USD
});
isArray seçeneği kritiktir. XML'inizde bazen bir öğe bazen de birçok öğe içerebilen bir liste elementi varsa, fast-xml-parser bir öğe için nesne, birçok öğe için dizi döndürür. isArray seçeneği adlandırılmış etiketler için tutarlı dizi davranışı zorlar — tekrarlanabileceğini bildiğiniz elementler için her zaman kullanın.

Node.js'de Hata Yönetimi

js
import { XMLParser, XMLValidator } from 'fast-xml-parser';

function parseXmlSafely(xmlString) {
  // Önce doğrula — true veya hata nesnesi döndürür
  const validation = XMLValidator.validate(xmlString);
  if (validation !== true) {
    throw new Error(`Invalid XML: ${validation.err.msg} at line ${validation.err.line}`);
  }

  const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: '@_' });
  return parser.parse(xmlString);
}

try {
  const data = parseXmlSafely(xmlString);
  console.log(data);
} catch (err) {
  console.error('XML parsing failed:', err.message);
}

İlgili Araçlar

JavaScript projelerinde XML ile çalışırken: XML Biçimlendirici küçültülmüş yanıtları güzelce biçimlendirmek için, XML Doğrulayıcı ayrıştırmadan önce iyi biçimliliği kontrol etmek için, XML XPath Test Aracı XPath sorgularını denemek için, ve XML'den JSON'a daha basit bir yapıya dönüştürmek istiyorsanız.

Özet

Tarayıcıda, 'application/xml' ile DOMParser temel tercihinizdir — sadece parsererror'u kontrol etmeyi unutmayın. Ad alanlı XML için getElementsByTagNameNS veya ad alanı çözücüyle XPath kullanın. Node.js'de fast-xml-parser DOM yükü olmadan temiz JavaScript nesneleri sunar. Buradaki desenler gerçek dünya XML ayrıştırma senaryolarının %95'ini kapsar — SOAP yanıtları, RSS beslemeleri, yapılandırma dosyaları ve daha fazlası.