2011-12-22 20 views
13

Ayrıştırmam gereken bir XML akışı var. Sadece bir kez yapmam ve java nesnelerini yapmam gerektiğinden, SAX doğal tercih gibi görünüyor. DefaultHandler'ı genişletiyorum ve startElement, endElement ve karakter yöntemlerini uygulayarak, mevcut okuma değerini kaydettiğim (karakter yönteminde alınmış) sınıfımdaki üyelerim var.Java SAX Ayrıştırma

İhtiyacım olanı yapmaya çalışırken sorunum yok, ancak kodum oldukça karmaşık ve eminim bunun için bir neden yok ve işleri farklı yapabilirim. Aynı etiket adları dosyanın çeşitli alanlarda kullanıldığını fark edince Benim sorunum başladı

<players> 
    <player> 
    <id></id> 
    <name></name> 
    <teams total="2"> 
     <team> 
     <id></id> 
     <name></name> 
     <start-date> 
      <year>2009</year> 
      <month>9</month> 
     </start-date> 
     <is-current>true</is-current> 
     </team> 
     <team> 
     <id></id> 
     <name></name> 
     <start-date> 
      <year>2007</year> 
      <month>11</month> 
     </start-date> 
     <end-date> 
      <year>2009</year> 
      <month>7</month> 
     </end-date> 
     </team> 
    </teams> 
    </player> 
</players> 

: benim XML yapısı böyle bir şeydir. Örneğin, hem oyuncu hem de takım için id ve isim vardır. Java sınıfları Oyuncu ve Takımımın örneklerini oluşturmak istiyorum. Ayrıştırma yaparken boolean bayraklarını ekipler bölümünde olduğumu söyleyerek tuttum. Bu yüzden, endElement'te ismin bir takımın ismi olduğunu, oyuncunun adını ve benzeri olmadığını bileceğim. gibi benim kod nasıl göründüğünü

İşte: Ben takımlara ek olarak bir oyuncuya daha fazla düğüm var ve bu düğümler de adı ve kimliği gibi etiketine sahip benim gerçek senaryoda yana

public class MyParser extends DefaultHandler { 

    private String currentValue; 
    private boolean inTeamsSection = false; 
    private Player player; 
    private Team team; 
    private List<Team> teams; 

    public void characters(char[] ch, int start, int length) throws SAXException { 
     currentValue = new String(ch, start, length); 
    } 

    public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { 
     if(name.equals("player")){ 
      player = new Player(); 
     } 
     if (name.equals("teams")) { 
      inTeamsSection = true; 
      teams = new ArrayList<Team>(); 
     } 
     if (name.equals("team")){ 
      team = new Team(); 
     } 
    } 

    public void endElement(String uri, String localName, String name) throws SAXException { 
     if (name.equals("id")) { 
      if(inTeamsSection){ 
       team.setId(currentValue); 
      } 
      else{ 
       player.setId(currentValue); 
      } 
     } 
     if (name.equals("name")){ 
      if(inTeamsSection){ 
       team.setName(currentValue); 
      } 
      else{ 
       player.setName(currentValue); 
      } 
     } 
     if (name.equals("team")){ 
      teams.add(team); 
     } 
     if (name.equals("teams")){ 
      player.setTeams(teams); 
      inTeamsSection = false; 
     } 
    } 
} 

, kendimi berbat bulundu inTeamsSection'a benzeyen birkaç boole ile birlikte ve endElement yöntemim birçok koşulla uzun ve karmaşık hale gelir.

Farklı ne yapmalıyım? Örneğin bir isim etiketinin neye ait olduğunu nasıl bilebilirim?

Teşekkürler!

+1

SAX kullanmanın 7 yıl önce doğal bir seçim olduğunu söyleyebilirim. Şu anda doğal seçim JAXB (veya Xtream veya XmlBeans veya JibX) – Tarlog

+0

kullanmaktır. Bazen sadece el ile ayrıştırma yapmak zorunda. XML nesnelerini XML nesnelerine dönüştürdüğünüzde, bu çok iyi bir fikir değildir. –

+0

@ ʘleg - Bir StAX XMLStreamReader'dan marjinal olmayan nesnelere JAXB kullanırsanız, bellek kısıtlamalarını yönetmek için daha büyük bir belgenin alt sınırlarını kaldırabilirsiniz. –

cevap

20

Bir SAX ayrıştırıcısı yazılırken net bir numara vardır: Ayrıştırma sırasında bir XMLReader'ın ContentHandler değiştirilmesine izin verilir. Bu, ayrıştırma mantığını farklı öğeler için birden çok sınıfa ayırmanıza olanak tanır, bu da 'u daha modüler ve yeniden kullanılabilir hale getirmeyi sağlar. Bir işleyici son elemanını gördüğü zaman ana sayfasına geri döner. Uyguladığınız işleyicilerin sayısı, ’a bırakılacaktır.Kod şu şekilde görünecektir:

public class RootHandler extends DefaultHandler { 
    private XMLReader reader; 
    private List<Team> teams; 

    public RootHandler(XMLReader reader) { 
     this.reader = reader; 
     this.teams = new LinkedList<Team>(); 
    } 

    public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { 
     if (name.equals("team")) { 
      // Switch handler to parse the team element 
      reader.setContentHandler(new TeamHandler(reader, this)); 
     } 
    } 
} 

public class TeamHandler extends DefaultHandler { 
    private XMLReader reader; 
    private RootHandler parent; 
    private Team team; 
    private StringBuilder content; 

    public TeamHandler(XMLReader reader, RootHandler parent) { 
     this.reader = reader; 
     this.parent = parent; 
     this.content = new StringBuilder(); 
     this.team = new Team(); 
    } 

    // characters can be called multiple times per element so aggregate the content in a StringBuilder 
    public void characters(char[] ch, int start, int length) throws SAXException { 
     content.append(ch, start, length); 
    } 

    public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { 
     content.setLength(0); 
    } 

    public void endElement(String uri, String localName, String name) throws SAXException { 
     if (name.equals("name")) { 
      team.setName(content.toString()); 
     } else if (name.equals("team")) { 
      parent.addTeam(team); 
      // Switch handler back to our parent 
      reader.setContentHandler(parent); 
     } 
    } 
} 
+0

Subteams varsa, Oyuncular vs hepsi birbirleriyle referans içermeli, bu da _VERY_ sıkı kuplaj ile sonuçlanacaktı? –

+1

Her bir işleyicinin ana işleyicisi ve olası çocuk işleyicileri hakkında bilgi sahibi olması gerekir, bu nedenle kesinlikle bazı bağlamalar var. Fakat örneğin, 'başlangıç ​​tarihi' işleyicisinin 'oynatıcı' için işleyiciyi bilmesi gerekmeyecektir. –

+0

Teşekkürler, şimdi bu hileyi kullanıyorum ve benim için harika çalışıyor. Bu kullanım durumu için ihtiyacım olan şey. – Haji

1

Kendinizi ayrıştırma işlemini durdurmanızı ve iyi XML veri bağlama kitaplığı almanızı kesinlikle öneririz. XStream (http://x-stream.github.io/) kişisel favori olabilir, ancak birçok farklı kütüphane var. POJO'larınızı, herhangi bir yapılandırma gerekmeden (XML yapılarıyla eşleştirmek için özellik adlarını ve çoğaltmayı kullanırsanız) yerinde bile ayrıştırabilir.

0

Ben çok benzer, ancak bunun yerine ben varım, ben player veya team olmayan null olmanın test ne durumda söyle boolean bayrakları sahip bir şeyler yapmak. İşleri biraz daha iyi yapar. Bu, ilgili öğeye ekledikten sonra, her öğenin sonunu algıladığınızda bunları null olarak ayarlamanızı gerektirir.

0

Daha güzel bir koda ihtiyacınız varsa lütfen StAX kullanın, bu comparison of all XML parsing APIs StAX'ın çok daha iyi bir seçenek olduğunu gösterir. Çoğu testte

StAX performance diğer API uygulamalarından daha iyidir.

Bu yüzden, bazı eski yazılımlarla ilgili programlama yapmıyorsanız, SAX ile devam etme konusunda hiçbir neden görmüyorum.

2

Bu sizin gereksinimleri hakkında daha fazla bilmeden tavsiye etmek zor, ama "benim kod oldukça karmaşık var" diye şaşırırlar gerçeği seçtiğiniz zaman iyi bilgilendirilmiş olmadığını düşündürmektedir SAX. SAX, çok yüksek performansa sahip, düşük seviyeli bir programlama arabirimidir, ancak çözümleyici sizin için çok daha az çalışmaktadır ve bu nedenle kendiniz çok daha fazla iş yapmanız gerekir.

İlgili konular