2011-01-28 19 views
57

私はこれに続くtutorialです。SAXパーサーを使用してXMLを解析する方法

素晴らしいですが、最後の要素が1つの文字列ではなく、すべての文字列で配列を返すことをお勧めします。

どのようにすればいいですか?

+0

をあなたのXML構造の抽象的な描写を投稿してくださいもらえますか? –

+0

http://dearfriends.se/category/blog/feed/rss/ - >ソースを表示 – Johan

答えて

178

このようにRSSフィードを解析するXMLパーサを構築したいとします。

<rss version="0.92"> 
<channel> 
    <title>MyTitle</title> 
    <link>http://myurl.com</link> 
    <description>MyDescription</description> 
    <lastBuildDate>SomeDate</lastBuildDate> 
    <docs>http://someurl.com</docs> 
    <language>SomeLanguage</language> 

    <item> 
     <title>TitleOne</title> 
     <description><![CDATA[Some text.]]></description> 
     <link>http://linktoarticle.com</link> 
    </item> 

    <item> 
     <title>TitleTwo</title> 
     <description><![CDATA[Some other text.]]></description> 
     <link>http://linktoanotherarticle.com</link> 
    </item> 

</channel> 
</rss> 

ここでは、2つのSAX実装を使用できます。 org.xml.saxまたはandroid.saxの実装を使用してください。短い手書きの例を投稿した後で、私はプロと詐欺の両方について説明します。

android.sax実装

android.sax実装で始まるのをしてみましょう。

まず、RootElementElementオブジェクトを使用してXML構造を定義する必要があります。

いずれにしても、データを保持するPOJO(Plain Old Java Objects)を使用します。ここに必要なPOJOがあります。

Channel.java

public class Channel implements Serializable { 

    private Items items; 
    private String title; 
    private String link; 
    private String description; 
    private String lastBuildDate; 
    private String docs; 
    private String language; 

    public Channel() { 
     setItems(null); 
     setTitle(null); 
     // set every field to null in the constructor 
    } 

    public void setItems(Items items) { 
     this.items = items; 
    } 

    public Items getItems() { 
     return items; 
    } 

    public void setTitle(String title) { 
     this.title = title; 
    } 

    public String getTitle() { 
     return title; 
    } 
    // rest of the class looks similar so just setters and getters 
} 

このクラスは、あなたがBundleにそれを入れて、それで何かを行うことができますので、Serializableインタフェースを実装しています。

ここでアイテムを保持するクラスが必要です。この場合、私はちょうどArrayListクラスを拡張しようとしています。これだけ

Items.java

public class Items extends ArrayList<Item> { 

    public Items() { 
     super(); 
    } 

} 

当社の商品コンテナの。各項目のデータを保持するクラスが必要になりました。

Item.java

public class Item implements Serializable { 

    private String title; 
    private String description; 
    private String link; 

    public Item() { 
     setTitle(null); 
     setDescription(null); 
     setLink(null); 
    } 

    public void setTitle(String title) { 
     this.title = title; 
    } 

    public String getTitle() { 
     return title; 
    } 

    // same as above. 

} 

例:あなたが見ることができるよう

public class Example extends DefaultHandler { 

    private Channel channel; 
    private Items items; 
    private Item item; 

    public Example() { 
     items = new Items(); 
    } 

    public Channel parse(InputStream is) { 
     RootElement root = new RootElement("rss"); 
     Element chanElement = root.getChild("channel"); 
     Element chanTitle = chanElement.getChild("title"); 
     Element chanLink = chanElement.getChild("link"); 
     Element chanDescription = chanElement.getChild("description"); 
     Element chanLastBuildDate = chanElement.getChild("lastBuildDate"); 
     Element chanDocs = chanElement.getChild("docs"); 
     Element chanLanguage = chanElement.getChild("language"); 

     Element chanItem = chanElement.getChild("item"); 
     Element itemTitle = chanItem.getChild("title"); 
     Element itemDescription = chanItem.getChild("description"); 
     Element itemLink = chanItem.getChild("link"); 

     chanElement.setStartElementListener(new StartElementListener() { 
      public void start(Attributes attributes) { 
       channel = new Channel(); 
      } 
     }); 

     // Listen for the end of a text element and set the text as our 
     // channel's title. 
     chanTitle.setEndTextElementListener(new EndTextElementListener() { 
      public void end(String body) { 
       channel.setTitle(body); 
      } 
     }); 

     // Same thing happens for the other elements of channel ex. 

     // On every <item> tag occurrence we create a new Item object. 
     chanItem.setStartElementListener(new StartElementListener() { 
      public void start(Attributes attributes) { 
       item = new Item(); 
      } 
     }); 

     // On every </item> tag occurrence we add the current Item object 
     // to the Items container. 
     chanItem.setEndElementListener(new EndElementListener() { 
      public void end() { 
       items.add(item); 
      } 
     }); 

     itemTitle.setEndTextElementListener(new EndTextElementListener() { 
      public void end(String body) { 
       item.setTitle(body); 
      } 
     }); 

     // and so on 

     // here we actually parse the InputStream and return the resulting 
     // Channel object. 
     try { 
      Xml.parse(is, Xml.Encoding.UTF_8, root.getContentHandler()); 
      return channel; 
     } catch (SAXException e) { 
      // handle the exception 
     } catch (IOException e) { 
      // handle the exception 
     } 

     return null; 
    } 

} 

は、今では非常に簡単な例でした。 android.sax SAX実装を使用する主な利点は、解析する必要があるXMLの構造を定義してから、適切な要素にイベントリスナーを追加することができることです。欠点は、コードがかなり繰り返して肥大化することです。

org.xml.saxの実装

org.xml.sax SAXハンドラの実装は少し異なっています。

ここでは、XML構造を指定または宣言するのではなく、イベントをリッスンするだけです。最も広く使用されているものは、イベントを次のとおりです。

  • ドキュメントスタート
  • ドキュメントエンド
  • 要素スタート
  • 要素エンド
  • 要素スタートと要素の端部との間の文字

例上記のChannelオブジェクトを使用したハンドラ実装は、次のようになります。

public class ExampleHandler extends DefaultHandler { 

    private Channel channel; 
    private Items items; 
    private Item item; 
    private boolean inItem = false; 

    private StringBuilder content; 

    public ExampleHandler() { 
     items = new Items(); 
     content = new StringBuilder(); 
    } 

    public void startElement(String uri, String localName, String qName, 
      Attributes atts) throws SAXException { 
     content = new StringBuilder(); 
     if(localName.equalsIgnoreCase("channel")) { 
      channel = new Channel(); 
     } else if(localName.equalsIgnoreCase("item")) { 
      inItem = true; 
      item = new Item(); 
     } 
    } 

    public void endElement(String uri, String localName, String qName) 
      throws SAXException { 
     if(localName.equalsIgnoreCase("title")) { 
      if(inItem) { 
       item.setTitle(content.toString()); 
      } else { 
       channel.setTitle(content.toString()); 
      } 
     } else if(localName.equalsIgnoreCase("link")) { 
      if(inItem) { 
       item.setLink(content.toString()); 
      } else { 
       channel.setLink(content.toString()); 
      } 
     } else if(localName.equalsIgnoreCase("description")) { 
      if(inItem) { 
       item.setDescription(content.toString()); 
      } else { 
       channel.setDescription(content.toString()); 
      } 
     } else if(localName.equalsIgnoreCase("lastBuildDate")) { 
      channel.setLastBuildDate(content.toString()); 
     } else if(localName.equalsIgnoreCase("docs")) { 
      channel.setDocs(content.toString()); 
     } else if(localName.equalsIgnoreCase("language")) { 
      channel.setLanguage(content.toString()); 
     } else if(localName.equalsIgnoreCase("item")) { 
      inItem = false; 
      items.add(item); 
     } else if(localName.equalsIgnoreCase("channel")) { 
      channel.setItems(items); 
     } 
    } 

    public void characters(char[] ch, int start, int length) 
      throws SAXException { 
     content.append(ch, start, length); 
    } 

    public void endDocument() throws SAXException { 
     // you can do something here for example send 
     // the Channel object somewhere or whatever. 
    } 

} 

は、私は本当にandroid.sax 1上であなたにこのハンドラ実装のいずれかの本当の利点を伝えることはできません正直に言うと。しかし、私はあなたが今明らかにされるべき不利な点を教えてくれます。 startElementメソッドのelse ifステートメントを見てください。タグ<title>linkdescriptionがあるという事実のために、私たちは現時点でXML構造でそこを追跡しなければなりません。つまり、開始タグ<item>が発生した場合は、inItemフラグをtrueに設定して正しいデータを正しいオブジェクトにマップし、</item>タグが見つかった場合にendElementメソッドでフラグをfalseに設定します。私たちがそのitemタグで完了したことを伝えるために。

この例では、それを管理するのはかなり簡単ですが、異なるレベルの繰り返しタグでより複雑な構造を解析する必要があります。ここではEnumを使用して現在の状態を設定し、多くのスイッチ/ケースステートメントを使用して現在地を確認するか、タグスタックを使用して何らかの種類のタグトラッカーになるより洗練されたソリューションを使用する必要があります。

+0

@Adinia両方の実装を一緒に使用することは問題ありません。あなたがなぜそれをするのか知っている限り、それをすることに問題はありません。 –

+0

@ octavian-damiean私のコードがうまくいたのは本当ですが、どうしてすべての行を書いたのか分からなかった。私はそれぞれの仕組みがどのように働いているのか理解していたので、ちょっときれいにしようとしています。それで、両方を一緒に使うことは大丈夫だというメモに感謝します。 – Adinia

+0

@Adinia私は参照してください。どういたしまして。あなたはそれについてさらに質問がある場合は、クールな[Androidチャットルーム](http://chat.stackoverflow.com/rooms/15/android)に参加することもできます。 –

2

多くの問題では、目的ごとに異なる種類のxmlファイルを使用する必要があります。私はこの巨大さを掴み、自分の経験からこのすべてが必要なことを伝えようとはしません。

Java、おそらく、私のお気に入りのプログラミング言語。さらに、この愛はあなたが何か問題を解決することができ、自転車を思い付くことが必要ではないという事実によって強化されています。

このように、クライアントがデータベースサーバにエントリをリモートで作成できるようにするデータベースを実行するクライアント/サーバの束を作成することになりました。入力データなどを確認する必要はありませんが、それは問題ではありません。

作業の原則として、わたしは躊躇せずに、xmlファイルの形式で情報の送信を選択しました。以下のタイプのうち:

<? xml version = "1.0" encoding = "UTF-8" standalone = "no"?> 
<doc> 
<id> 3 </ id> 
<fam> Ivanov </ fam> 
<name> Ivan </ name> 
<otc> I. </ otc> 
<dateb> 10-03-2005 </ dateb> 
<datep> 10-03-2005 </ datep> 
<datev> 10-03-2005 </ datev> 
<datebegin> 09-06-2009 </ datebegin> 
<dateend> 10-03-2005 </ dateend> 
<vdolid> 1 </ vdolid> 
<specid> 1 </ specid> 
<klavid> 1 </ klavid> 
<stav> 2.0 </ stav> 
<progid> 1 </ progid> 
</ doc> 

医師の施設に関する情報であることを除いて、それ以上読むのが簡単になります。姓、名、一意のIDなど。一般に、データ系列。このファイルは安全にサーバー側にあり、ファイルの解析を開始します。 (DOM対SAX)を解析する二つの選択肢のうち

は、私は彼がより明るく働くという事実のSAXビューを選択し、彼は最初に私が手:)

Soのに落ちました。ご存知のように、パーサーで正常に動作するためには、必要なメソッドDefaultHandlerをオーバーライドする必要があります。まず、必要なパッケージを接続します。

import org.xml.sax.helpers.DefaultHandler; 
import org.xml.sax. *; 

今、私たちは、のメソッドstartDocument()を見てみましょう私たちのパーサ

public class SAXPars extends DefaultHandler { 
   ... 
} 

を書き始めることができます。彼は、名前が意味するように、文書の始めのイベントに反応する。ここでは、そのようなメモリ割り当てなどのさまざまなアクションを掛けることができる、または値をリセットするために、私たちの例では、これだけの適切なメッセージの仕事の始まりマークし、非常に単純です:

Override 
public void startDocument() throws SAXException { 
   System.out.println ("Start parse XML ..."); 
} 

次へ。パーサーは文書を通過し、その構造の要素を満たします。 startElement()メソッドを開始します。そして、実際には、彼の外観は:startElement(String namespaceURI、String localName、String qName、Attributes atts)。ここでnamespaceURIは名前空間、localNameは要素のローカル名、qNameはローカル名と名前空間(コロンで区切られた)の組み合わせ、attsはこの要素の属性です。この場合、すべて単純です。 qName'omを使用して、それをいくつかのサービスラインthisElementにスローするだけで十分です。したがって、私たちは、現時点で要素がどのマークであるかをマークします。

@Override 
public void startElement (String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { 
   thisElement = qName; 
} 

次は、その意味になる項目です。ここにはcharacters()メソッドが含まれています。彼は次の形式を持っています:characters(char [] ch、int start、int length)ここではすべてが明確です。 ch - この要素内で文字列自体が自己重要であるファイル。 startとlength - 行の開始点と長さを示すサービスの数。

@Override 
public void characters (char [] ch, int start, int length) throws SAXException { 
   if (thisElement.equals ("id")) { 
      doc.setId (new Integer (new String (ch, start, length))); 
   } 
   if (thisElement.equals ("fam")) { 
      doc.setFam (new String (ch, start, length)); 
   } 
   if (thisElement.equals ("name")) { 
      doc.setName (new String (ch, start, length)); 
   } 
   if (thisElement.equals ("otc")) { 
      doc.setOtc (new String (ch, start, length)); 
   } 
   if (thisElement.equals ("dateb")) { 
      doc.setDateb (new String (ch, start, length)); 
   } 
   if (thisElement.equals ("datep")) { 
      doc.setDatep (new String (ch, start, length)); 
   } 
   if (thisElement.equals ("datev")) { 
      doc.setDatev (new String (ch, start, length)); 
   } 
   if (thisElement.equals ("datebegin")) { 
      doc.setDatebegin (new String (ch, start, length)); 
   } 
   if (thisElement.equals ("dateend")) { 
      doc.setDateend (new String (ch, start, length)); 
   } 
   if (thisElement.equals ("vdolid")) { 
      doc.setVdolid (new Integer (new String (ch, start, length))); 
   } 
   if (thisElement.equals ("specid")) { 
      doc.setSpecid (new Integer (new String (ch, start, length))); 
   } 
   if (thisElement.equals ("klavid")) { 
      doc.setKlavid (new Integer (new String (ch, start, length))); 
   } 
   if (thisElement.equals ("stav")) { 
      doc.setStav (new Float (new String (ch, start, length))); 
   } 
   if (thisElement.equals ("progid")) { 
      doc.setProgid (new Integer (new String (ch, start, length))); 
   } 
} 

ああ、はい。忘れそうだった。その目的はナパルシェニを折りたたむことであるので、データは医師のタイプに話す。このクラスは定義されており、必要なすべてのセッターgetterを持っています。

次の明白な要素が終了し、それに次が続きます。 endElement()を終了する責任があります。商品が終了し、現時点では何でもできることを私達に伝えます。続行します。要素を浄化する。

@Override 
public void endElement (String namespaceURI, String localName, String qName) throws SAXException { 
   thisElement = ""; 
} 

このようにドキュメント全体が表示されるので、ファイルの最後に来ます。作業endDocument()。それで、私たちはメモリを解放し、いくつかの診断的な印刷などを行うことができます。私たちの場合、構文解析が終わるところを書いてください。

@Override 
public void endDocument() { 
   System.out.println ("Stop parse XML ..."); 
} 

xmlの形式を解析するクラスがあります。私は、トピックを簡単にSAXパーサの本質を提示する助けを願ってい

import org.xml.sax.helpers.DefaultHandler; 
import org.xml.sax. *; 
  
public class SAXPars extends DefaultHandler { 
  
Doctors doc = new Doctors(); 
String thisElement = ""; 
  
public Doctors getResult() { 
   return doc; 
} 
  
@Override 
public void startDocument() throws SAXException { 
   System.out.println ("Start parse XML ..."); 
} 
  
@Override 
public void startElement (String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { 
   thisElement = qName; 
} 
  
@Override 
public void endElement (String namespaceURI, String localName, String qName) throws SAXException { 
   thisElement = ""; 
} 
  
@Override 
public void characters (char [] ch, int start, int length) throws SAXException { 
   if (thisElement.equals ("id")) { 
      doc.setId (new Integer (new String (ch, start, length))); 
   } 
   if (thisElement.equals ("fam")) { 
      doc.setFam (new String (ch, start, length)); 
   } 
   if (thisElement.equals ("name")) { 
      doc.setName (new String (ch, start, length)); 
   } 
   if (thisElement.equals ("otc")) { 
      doc.setOtc (new String (ch, start, length)); 
   } 
   if (thisElement.equals ("dateb")) { 
      doc.setDateb (new String (ch, start, length)); 
   } 
   if (thisElement.equals ("datep")) { 
      doc.setDatep (new String (ch, start, length)); 
   } 
   if (thisElement.equals ("datev")) { 
      doc.setDatev (new String (ch, start, length)); 
   } 
   if (thisElement.equals ("datebegin")) { 
      doc.setDatebegin (new String (ch, start, length)); 
   } 
   if (thisElement.equals ("dateend")) { 
      doc.setDateend (new String (ch, start, length)); 
   } 
   if (thisElement.equals ("vdolid")) { 
      doc.setVdolid (new Integer (new String (ch, start, length))); 
   } 
   if (thisElement.equals ("specid")) { 
      doc.setSpecid (new Integer (new String (ch, start, length))); 
   } 
   if (thisElement.equals ("klavid")) { 
      doc.setKlavid (new Integer (new String (ch, start, length))); 
   } 
   if (thisElement.equals ("stav")) { 
      doc.setStav (new Float (new String (ch, start, length))); 
   } 
   if (thisElement.equals ("progid")) { 
      doc.setProgid (new Integer (new String (ch, start, length))); 
   } 
} 
  
@Override 
public void endDocument() { 
   System.out.println ("Stop parse XML ..."); 
} 
} 

:ここでは、フルテキストです。

厳密には最初の記事を判断しないでください:)私はそれが少なくとも有用な人だったと思います。

UPD:このパーサを実行するには、このコードを使用することができます:

SAXParserFactory factory = SAXParserFactory.newInstance(); 
SAXParser parser = factory.newSAXParser(); 
SAXPars saxp = new SAXPars(); 
  
parser.parse (new File ("..."), saxp); 

関連する問題