XML ayrıştırma teknikleri


11

Her zaman XML'i işlemek için hantal buldum. Bir XML ayrıştırıcısı uygulamaktan bahsetmiyorum: XML düğümünü düğüm tarafından işleyen SAX ayrıştırıcısı gibi mevcut bir akış tabanlı ayrıştırıcıyı kullanmaktan bahsediyorum .

Evet, bu ayrıştırıcılar için çeşitli API'leri öğrenmek gerçekten kolay, ancak XML'i işleyen koda baktığımda her zaman biraz kıvrımlı buluyorum. Temel sorun, bir XML belgesinin mantıksal olarak tek tek düğümlere ayrılması gibi görünmektedir ve yine de veri türleri ve nitelikleri genellikle gerçek verilerden, bazen birden fazla iç içe yerleştirme düzeyiyle ayrılmaktadır. Bu nedenle, belirli bir düğümü tek tek işlerken, nerede olduğumuzu ve daha sonra ne yapmamız gerektiğini belirlemek için çok fazla ekstra durumun korunması gerekir.

Örneğin, tipik bir XML belgesinden bir snippet verildiğinde:

<book>
  <title>Blah blah</title>
  <author>Blah blah</author>
  <price>15 USD</price>
</book>

... Kitap başlığı içeren bir metin düğümü ile karşılaştığımda nasıl belirleyebilirim? Her aradığımızda bize XML belgesinde bir sonraki düğümü veren, yineleyici gibi davranan basit bir XML ayrıştırıcımız olduğunu varsayalım XMLParser.getNextNode(). Kaçınılmaz olarak kendimi aşağıdaki gibi kod yazma bulmak:

boolean insideBookNode = false;
boolean insideTitleNode = false;

while (!XMLParser.finished())
{
    ....
    XMLNode n = XMLParser.getNextNode();

    if (n.type() == XMLTextNode)
    {
        if (insideBookNode && insideTitleNode)
        {
            // We have a book title, so do something with it
        }
    }
    else
    {
        if (n.type() == XMLStartTag)
        {
            if (n.name().equals("book")) insideBookNode = true
            else if (n.name().equals("title")) insideTitleNode = true;
        }
        else if (n.type() == XMLEndTag)
        {
            if (n.name().equals("book")) insideBookNode = false;
            else if (n.name().equals("title")) insideTitleNode = false;
        }
    }
}

Temel olarak, XML işleme, daha önce bulduğumuz üst düğümleri belirtmek için kullanılan çok sayıda durum değişkeni ile birlikte, büyük, durum-makine odaklı bir döngüye dönüşür. Aksi takdirde, tüm iç içe etiketlerin izlenmesi için bir yığın nesnesinin korunması gerekir. Bu hızla hataya açık hale gelir ve bakımı zorlaşır.

Yine, sorun, ilgilendiğimiz verilerin doğrudan tek bir düğümle ilişkili olmaması gibi görünüyor. Tabii ki, XML'i şöyle yazarsak:

<book title="Blah blah" author="blah blah" price="15 USD" />

... ama nadiren XML gerçekte böyle kullanılır. Çoğunlukla üst düğümlerin alt öğesi olarak metin düğümlerimiz vardır ve bir metin düğümünün ne anlama geldiğini belirlemek için üst düğümleri takip etmemiz gerekir.

Yani ... yanlış bir şey mi yapıyorum? Daha iyi bir yol var mı? XML akışı tabanlı bir ayrıştırıcı kullanmak hangi noktada çok hantal hale gelir, böylece tam teşekküllü bir DOM ayrıştırıcısı gerekli hale gelir? Akış tabanlı ayrıştırıcılarla XML işlerken diğer programcılardan ne tür deyimler kullandıklarını duymak istiyorum. Akış tabanlı XML ayrıştırma her zaman büyük bir durum makinesine dönüşmeli mi?


2
Bir .net dili kullanıyorsanız, linq to xml aka XLinq'e bakmalısınız.
Muad'Dib

Teşekkür ederim, bu sorunu yaşayan tek kişi olduğumu sanıyordum. Açıkçası, bütün XML formatını genellikle bir yardımdan ziyade bir engel olarak görüyorum. Evet, çok sayıda yapılandırılmış verinin küçük bir metin dosyasında depolanmasına izin verir. Ancak, daha sonra veya daha az önemli bir şeyi göz ardı etmediğinizin garantisi olmadan, 20'den fazla derse ihtiyacınız varsa ve bir şeyleri anlamanız için. Monty Python'un Kutsal Kâse'deki tavşan gibi.
Elise van Looij

Yanıtlar:


9

Bana göre soru tam tersi. Bir XML Belgesi hangi noktada bu kadar hantal hale gelir, DOM yerine SAX kullanmaya başlamanız gerekir?

SAX'ı yalnızca çok büyük, belirsiz boyutlu bir veri akışı için kullanırdım; veya XML'in çağırması amaçlanan davranış gerçekten olay güdümlü ve dolayısıyla SAX benzeri ise.

Verdiğiniz örnek bana çok DOM gibi görünüyor.

  1. XML'yi yükleyin
  2. Başlık düğüm (ler) ini çıkarın ve "onlarla bir şeyler yapın".

EDIT: Ben de hatalı biçimlendirilmiş akarsu için SAX kullanmak istiyorum, ama nerede veri elde en iyi tahmin yapmak istiyorum.


2
Bence bu iyi bir nokta. DOM için çok büyük olan belgeleri ayrıştırıyorsanız, XML
Dean Harding

1
+1: Seçenek göz önüne alındığında, daima DOM ile giderdim. Ne yazık ki, tasarım gereksinimlerimiz her zaman "herhangi bir boyut belgesini işleme yeteneği" ve "performansa sahip olmalı" dır ve DOM tabanlı çözümleri hemen hemen dışlar.
TMN

3
@TMN, ideal bir dünyada gereksinimlerin ilk etapta XML'i ekarte edeceğini söyledi.
SK-logic

1
@TMN, şu hayalet gereksinimlerden birine benziyor: "Tabii ki tüm belgelerimiz sadece 100KB ve gördüğümüz en büyük değer 1MB, ancak geleceğin ne tutacağını asla bilemezsiniz, bu yüzden seçeneklerimizi açık tutmalıyız ve sonsuz büyük belgeler için inşa "
Paul Butcher

@ Paul Butcher, asla bilemezsin. Yani, Wikipedia'nın bir dökümü 30GB XML gibi.
Kanal72

7

XML ile çok fazla çalışmıyorum, bence biraz, XML'i bir kütüphane ile ayrıştırmanın en iyi yollarından biri XPath kullanıyor.

Belirli bir düğümü bulmak için ağacı hareket ettirmek yerine, ona bir yol verirsiniz. Örneğinizde (sözde kodda), şöyle bir şey olurdu:

books = parent.xpath ("/ book") // Bu size tüm kitap düğümlerini verir
kitaplardaki her kitap için
    title = book.xpath ("/ title / text ()")
    author = book.xpath ("/ author / text ()")
    price = book.xpath ("/ price / text ()")

    // Verilerle bir şeyler yapın

XPath bundan çok daha güçlüdür, koşulları kullanarak (hem değerler hem de öznitelikler üzerinde) arama yapabilir, bir listede belirli bir düğümü seçebilir, seviyeleri ağaçta taşıyabilirsiniz. Nasıl kullanılacağına dair bilgi aramanızı öneririm, birçok ayrıştırma kütüphanesinde uygulanır (Python için .Net Framework sürümünü ve lxml kullanıyorum)


Eğer xml'nin yapılandırılma şeklini önceden biliyor ve güvenebiliyorsanız sorun yok. Bir öğenin genişliğinin bir düğümün niteliği olarak mı yoksa bir öğenin boyut düğümündeki nitelik düğümü olarak mı belirtileceğini bilmiyorsanız, XPath çok yardımcı olmayacaktır.
Elise van Looij

5

Akış tabanlı XML ayrıştırma her zaman büyük bir durum makinesine dönüşmeli mi?

Genellikle öyle, evet.

Tam teşekküllü bir DOM ayrıştırıcısı kullanmamı işaret etmem, dosyadaki hiyerarşinin bazı kısımlarını bellekte taklit etmem gerektiğinde, örneğin belge içindeki çapraz referansları çözebilmem gerektiğinde.


+1: DOM ile başlayın. SAX'tan kaçının.
S.Lott

veya vtd-xml ile
vtd-xml-author

4

Genel olarak ayrıştırma yalnızca bir durum makinesini kullanmaktır ve XML ayrıştırma farklı değildir. Akış tabanlı ayrıştırma her zaman bir güçlüktür, her zaman ata düğümlerini takip etmek için bir tür yığın oluşturmaya çalışırım ve bir etiketi veya yol kaydını kontrol eden ve bir olayı tetikleyen çok sayıda olay ve bir tür olay dağıtıcı tanımlarım biri eşleşirse. Çekirdek kod oldukça sıkı, ancak çoğunlukla bir yerde bir yapıdaki bir alana aşağıdaki metin düğümünün değerini atamaktan oluşan büyük bir olay işleyicileri ile sarılıyorum. İş mantığını da karıştırmanız gerekiyorsa oldukça kıllı olabilir.

Boyut veya performans sorunları aksi belirtilmedikçe her zaman DOM kullanırdım.


1

Tamamen dil agnostik değil, ama genellikle ayrıştırmayı düşünmek yerine XML'i nesnelere serileştiririm. Stratejileri ayrıştırma konusunda endişelenmeniz gereken tek şey, hız sorununuz varsa.


Ayrıştırma altında. Söz konusu XML, nesne serileştirmesinin çıktısı olmadığı ve hazır bir serileştirme kitaplığınız olmadığı sürece. Ama sonra bu soru ortaya çıkmıyor.

Birçok dilde / yığınta hazır inşa edilmiş serileştirme kitaplıkları bulunur.
Wyatt Barnett

Evet, ne olmuş yani? Puanlarım hala duruyor - vahşi ortamdaki tüm XML dosyaları böyle bir formatta gelmiyor ve bunu yapan bir dosyanız varsa, sadece bu serileştirme kitaplığını kullandığınız ve kendi başınıza hiçbir şeyi ayrıştırmadığınız için bu soruyu sormuyorsunuz , akışlardan veya başka türlü.

0

XPath kullanabiliyorsanız çok daha az hantal hale gelir. Net karada LINQ to XML de daha az çekici şeyleri özetler. ( Düzenle - bunlar elbette bir DOM yaklaşımı gerektirir)

Temel olarak, eğer akış temelli bir yaklaşım (yani bir DOM gerektiren güzel soyutlamalar kullanamazsınız) alıyorsanız, her zaman oldukça hantal olacağını düşünüyorum ve bunun herhangi bir yolu olduğundan emin değilim.


XPath kullanıyorsanız, DOM kullanıyorsunuz (evde yetiştirilen bir XPath değerlendiricisiyle kullanmıyorsanız).
TMN

evet, bu yüzden DOM gerektiren soyutlamalar hakkındaki yorumum ... ama açıklığa kavuşacağım, teşekkürler!
Steve

0

Size bir yineleyici veren bir ayrıştırıcı bulabilirseniz, bir lexer gibi davranmayı ve bir durum makine jeneratörü kullanmayı düşündünüz mü?

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.