[Android] XML Parser Android 2012. 3. 8. 16:25

XML에는 크게 DOM과 SAX 파서가 존재한다.

DOM은 트리 형식으로 문서를 읽으면서 전체 구조 파악 후 정보를 구하고 SAX는 순차적으로 문서를 읽으면서 정보를 차례대로 읽는 방식이다.

다음이 그 예제이다.

public class ImageViewActivity extends Activity{ 
 public void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);  
  setContentView(R.layout.main);
  Button call = (Button)findViewById(R.id.call);
  call.setOnClickListener(new Button.OnClickListener(){
   public void onClick(View v){
    String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<order><item>unit</item>"+
    "<item one=\"one1\" two=\"two2\">first</item>"+
    "<item one=\"one2\" two=\"two2\">second</item>"+
    "</order>";    
    try{
     DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();//자체가 추상 클래스임으로 빌더 객체를 얻고 난 다음 메서드로 문서를 파싱하면 Document 객체가 생성이 됨.
     DocumentBuilder builder = factory.newDocumentBuilder();
     InputStream stream = new ByteArrayInputStream(xml.getBytes("utf-8"));
     Document doc = builder.parse(stream);
     org.w3c.dom.Element order = doc.getDocumentElement();//루트 엘리먼트 가져옴
     NodeList items = order.getElementsByTagName("item");
     //한줄의 간단 경우
     //Node item = items.item(0);
     //Node text = item.getFirstChild();
     //다수의 아이템 경우
     String result = "";
     for(int i=0;i<items.getLength();i++){
      Node item = items.item(i);
      Node text = item.getFirstChild();//노드 탐색하는 형태 지정 함
      String name = text.getNodeValue();//getNodeName과 getNodeType을 이용하여 이름과 타입도 가져옴
      result+=name+" --- ";
      NamedNodeMap attrs = item.getAttributes();//속성 값을 가져오기 위함
      for(int j=0;j<attrs.getLength();j++){
       Node attr = attrs.item(j);
       result+=attr.getNodeName()+"="+attr.getNodeValue();
      }
      result+="\n";
     }
     EditText edit = (EditText)findViewById(R.id.edit);
     edit.setText(result);
    }
    catch(Exception ex){
     Toast.makeText(v.getContext(), ex.getMessage(), 0).show();
    }
   }
  });
 }
}

DOM은 속도가 빠르며 임의 노드를 여러번 읽지만 최초 시작이 조금 느리면서 문서 크기에 따라 메모리에 대한 부하가 커진다. 반면 SAX는 메모리를 거의 사용하지 않으며 최초 실행이 빠르다. 하지만 읽기만을 담당한다.

public class ImageViewActivity extends Activity {
 EditText edit;

 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  Button call = (Button) findViewById(R.id.call);// ��
  edit = (EditText) findViewById(R.id.edit);
  call.setOnClickListener(new Button.OnClickListener() {
   public void onClick(View v) {
    edit.setText("Test");
    String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
      + "<order><item>sss</item></order>";
    try {
     SAXParserFactory factory = SAXParserFactory.newInstance();
     SAXParser parser = factory.newSAXParser();
     XMLReader reader = parser.getXMLReader();
     SaxHandler handler = new SaxHandler();
     reader.setContentHandler(handler);
     InputStream stream = new ByteArrayInputStream(xml
       .getBytes("utf-8"));
     reader.parse(new InputSource(stream));
     
     edit.setText(handler.sb.toString());
    } catch (Exception ex) {
     Toast.makeText(v.getContext(), ex.getMessage(), 0).show();
    }
   }
  });
 }

 class SaxHandler extends DefaultHandler {
  boolean flag = false;
  StringBuilder sb = new StringBuilder();

  public void startDocument() {
  }

  public void endDocument() {
  }

 

  @Override
  public void startElement(String uri, String localName, String qName,
    org.xml.sax.Attributes attributes) throws SAXException {
   // TODO Auto-generated method stub
   Log.d("DATA", "startElement");
   // @Override
   if (localName.equals("item")) {
    flag = true;
   }
  }
  public void endElement(String uri, String localName, String qName) {
  }
  
  @Override
  public void characters(char[] chars, int start, int length) {
   // @Override
   Log.d("DATA", "startElement");
   if (flag) {
    sb.append(chars, start, length);
    flag = false;
   }
  }
 };
}

그 외에 XmlPullParser 라는 것이 있다. 이는 SAX와 유사하나 이벤트 발생시마다 핸들러 대신 루프 돌면서 이벤트를 직접 조사한다.

예제는 다음과 같다.

public class ImageViewActivity extends Activity {
 EditText edit;

 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  Button call = (Button) findViewById(R.id.call);
  edit = (EditText) findViewById(R.id.edit);
  call.setOnClickListener(new Button.OnClickListener() {
   public void onClick(View v) {
    edit.setText("Test");
    String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
      + "<order><item>sss</item></order>";
    boolean flag = false;
    String name = "";
    try {
     XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
     XmlPullParser parser = factory.newPullParser();
     parser.setInput(new StringReader(xml));
     
     int type = parser.getEventType();
     while(type!=XmlPullParser.END_DOCUMENT){
      switch(type){
      case XmlPullParser.START_DOCUMENT : break;
      case XmlPullParser.END_DOCUMENT : break;
      case XmlPullParser.START_TAG :
       if(parser.getName().equals("item")){
        flag = true;
       }
      case XmlPullParser.END_TAG : break;
      case XmlPullParser.TEXT :
       if(flag){
        name = parser.getText();
        flag = false;
       }
       break;
      }
      type = parser.next();
     }
     edit.setText(name);
    } catch (Exception ex) {
     Toast.makeText(v.getContext(), ex.getMessage(), 0).show();
    }
   }
  });
 }

 class SaxHandler extends DefaultHandler {
  boolean flag = false;
  StringBuilder sb = new StringBuilder();

  public void startDocument() {
  }

  public void endDocument() {
  }

 

  @Override
  public void startElement(String uri, String localName, String qName,
    org.xml.sax.Attributes attributes) throws SAXException {
   // TODO Auto-generated method stub
   Log.d("DATA", "startElement");
   // @Override
   if (localName.equals("item")) {
    flag = true;
   }
  }
  public void endElement(String uri, String localName, String qName) {
  }
  
  @Override
  public void characters(char[] chars, int start, int length) {
   // @Override
   Log.d("DATA", "startElement");
   if (flag) {
    sb.append(chars, start, length);
    flag = false;
   }
  }
 };
}