web-dev-qa-db-ja.com

SAXパーサーを使用してXMLを解析する方法

私はこれをフォローしています チュートリアル

それはうまく機能しますが、最後の要素を持つ単一の文字列ではなく、すべての文字列を持つ配列を返したいです。

これを行う方法はありますか?

58
Johan

したがって、このような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 Implementation

Android.sax実装から始めましょう。

最初に、RootElementおよびElementオブジェクトを使用して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
}

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

ここで、アイテムを保持するクラスが必要です。この場合、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 Implementation

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ハンドラーに対するこのハンドラー実装の実際の利点については、本当に説明できません。しかし、今のところかなり明白なはずの不利な点を説明することができます。 startElementメソッドのelse ifステートメントを見てください。タグ<title>linkおよびdescriptionがあるため、現在のXML構造でそれらを追跡する必要があります。つまり、<item>開始タグに遭遇した場合、inItemフラグをtrueに設定して、正しいデータを正しいオブジェクトにマップし、endElement</item>タグが見つかった場合、そのフラグをfalseに設定します。そのitemタグで処理が完了したことを示すため。

この例では、それを管理するのは非常に簡単ですが、異なるレベルでタグを繰り返すことで、より複雑な構造を解析する必要があります。そこでは、例えば現在の状態を設定するために列挙を使用し、現在の場所を確認するために多くのスイッチ/ケースのステートメネットを使用する必要があります。よりエレガントなソリューションは、タグスタックを使用する何らかのタグトラッカーです。

179

多くの問題では、さまざまな目的のためにさまざまな種類の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など。一般的に、データ系列。このファイルはサーバー側で安全に取得され、ファイルの解析を開始します。

2つのオプション解析(SAXとDOM)のうち、私は彼がより明るく動作するという事実のSAXビューを選択しました。

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

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

これでパーサーの作成を開始できます

public class SAXPars extends DefaultHandler {
   ... 
} 

メソッドstartDocument()から始めましょう。彼は、その名前が示すように、文書の最初の出来事に反応します。ここでは、メモリ割り当てなどのさまざまなアクションをハングアップしたり、値をリセットしたりできますが、この例は非常に単純なので、適切なメッセージの作業の開始をマークしてください:

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; 
} 

次に、会議アイテムはその意味に到達します。ここにはメソッド文字()が含まれます。彼の形式は次のとおりです。文字(char [] ch、int start、int length)。さて、ここではすべてが明確です。 ch-この要素内に文字列自体の重要性を含むファイル。 start and 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))); 
   } 
} 

ああ、はい。忘れそうだった。 naparsennyeのデータを折り畳むことを目的とするので、データは医師のタイプに話します。このクラスは定義されており、必要なすべてのセッター/ゲッターがあります。

次の明らかな要素は終了し、次の要素が続きます。 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の形式を解析するクラスを取得しました。全文は次のとおりです。

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 ..."); 
} 
} 

このトピックがSAXパーサーの本質を簡単に提示するのに役立つことを願っています。

最初の記事を厳密に判断しないでください:)少なくとも誰かが役に立つことを願っています。

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

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

2
public class MainActivity extends AppCompatActivity {
   ListView lvPcsPost;
    ArrayList<String> name;
    ArrayList<String> price;
    ArrayList<String> Description;
    LayoutInflater layoutInflater;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        lvPcsPost = (ListView) findViewById(R.id.lvPcsPost);
        name = new ArrayList<>();
        price = new ArrayList<>();
        Description = new ArrayList<>();
        new PostAsync().execute();
    }

    class PostAsync extends AsyncTask<Void, Void, Void> {
        ProgressDialog pd;
        XMLHelper helper;


        @Override
        protected void onPreExecute() {
            pd = ProgressDialog.show(MainActivity.this, "", "Loading...", true, false);
        }

        @Override
        protected Void doInBackground(Void... arg0) {
            helper = new XMLHelper();
            helper.get();
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            PostBaseAdapter postBaseAdapter = new PostBaseAdapter();
            lvPcsPost.setAdapter(postBaseAdapter);
            pd.dismiss();
        }

    }

    public class XMLHelper extends DefaultHandler {

        private String URL_MAIN = "http://uat.winitsoftware.com/ThemeManager/Data/Products/Products.xml";
        String TAG = "XMLHelper";

        Boolean currTag = false;
        String currTagVal = "";

        public void get() {
            try {
                SAXParserFactory factory = SAXParserFactory.newInstance();
                SAXParser mSaxParser = factory.newSAXParser();
                XMLReader mXmlReader = mSaxParser.getXMLReader();
                mXmlReader.setContentHandler(this);
                InputStream mInputStream = new URL(URL_MAIN).openStream();
                mXmlReader.parse(new InputSource(mInputStream));
            } catch (Exception e) {
                Log.e(TAG, "Exception: " + e.getMessage());
            }
        }

        @Override
        public void characters(char[] ch, int start, int length)
                throws SAXException {
            if (currTag) {
                currTagVal = currTagVal + new String(ch, start, length);
                currTag = false;
            }
        }

        @Override
        public void endElement(String uri, String localName, String qName)
                throws SAXException {
            currTag = false;

            if (localName.equalsIgnoreCase("Name"))
                name.add(currTagVal);

            else if (localName.equalsIgnoreCase("Description"))
             Description.add(currTagVal);

            else if (localName.equalsIgnoreCase("Price"))
              price.add(currTagVal);

        }
        @Override
        public void startElement(String uri, String localName, String qName,
                                 Attributes attributes) throws SAXException {
            Log.i(TAG, "TAG: " + localName);

            currTag = true;
            currTagVal = "";
            if (localName.equals("Products"));
        }
    }

    public class PostBaseAdapter extends BaseAdapter {

        public PostBaseAdapter() {

        }

        @Override
        public int getCount() {
            return name.size();
        }

        @Override
        public Object getItem(int position) {
            return name.get(position);
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            layoutInflater = LayoutInflater.from(getApplicationContext());

            convertView = layoutInflater.inflate(R.layout.list_item_post, parent, false);
            TextView  txtPrice = (TextView) convertView.findViewById(R.id.txtPrice);
            TextView  txtDescription = (TextView) convertView.findViewById(R.id.txtDescription);
            TextView   txtName = (TextView) convertView.findViewById(R.id.txtName);
            ImageView   image = (ImageView) convertView.findViewById(R.id.Image);
            ImageView  bigImage = (ImageView) convertView.findViewById(R.id.BigImage);

                txtPrice.setText("Price : "+price.get(position));
                 txtDescription.setText("Description : "+Description.get(position));
                txtName.setText("Name : "+name.get(position));

            return convertView;
        }
    }
}
0
vimal singh