C/Objective C/ios2012.07.22 11:14

- XML 파서

XML 파서는 XML 파일을 읽어들이면, 앞에서부터 순서대로 분석하기 시작한다. 그러다가 ‘태그’나 ‘텍스 트’가 발견될 때마다 잘라내서 ‘이런 것이 발견되었습니다. 어떻게 처리할까요?’라고 물어오므로, 그때마다 처리할 방법을 프로그램에서 지정해주어야 한다(이를 델리게이트 메서드라고 한다).

다시 말해, ‘XML 파일을 읽고, 태그나 텍스트를 만나면 자르기’ 처리까지만 해주기 때문에 ‘태그나 텍스트 를 처리할 방법’을 프로그램으로 만들어야 한다.



1) URL 오브젝트 생성

XML 파일을 의미하는 URL 문자열로부터 URL 오브젝트(NSURL)를 생성한다.

NSURL *URL오브젝트 = [NSURL URLWithString: URL 문자열];

2) URL 오브젝트를 사용해 XML 파서 생성
XML 파서를 만들 때 initWithContentsOfURL에서 읽어들일 XML 파일의 URL 오브젝트를 설정한다.

NSXMLParser *XML파서 = [[NSXMLParser alloc] initWithcontentsOfURL: URL오브젝트];

3) delegate를 self로 지정
delegate를 self로 지정하면 XML 파서에서 해석을 할 때 통지 대상이 self(현재 프로그램을 작성하고 있 는 곳)가 된다. ‘태그’나 ‘텍스트’를 발견할 때마다 현재 프로그램을 작성하고 있는 곳에 마련된 델리게이 트가 호출되어 분석할 수 있게 된다.

4) 해석 시작
해석을 시작하려면 XML 파서의 parse 메소드를 실행해야 한다. 이 메소드를 실행하면 XML 파일을 읽어 들여 해석을 시작한다.

5) 해석을 시작하면 무엇을 할 것인가? parserDidStartDocument
해석을 시작했을 때 호출되는 델리게이트 메서드는 parserDidStartDocument이다.
주로 데이터 초기화나 해석 준비를 행한다. 해석 중에 ‘지금 조사하고 있는 태그’를 알아야 하므로, 이를 기억해 둘 변수 등을 준비하기도 한다.

6) 시작 태그를 발견하면 무엇을 할 것인가? didStartElement
태그의 이름은 elementName에 문자열 형태로 들어온다. 태그에 붙은 속성은 attributeDict에 사전 형식 으로 설정되므로, 키워드를 사용해 꺼낸다. 시작 태그를 발견한 다음에는 텍스트 요소를 읽어들이므로, 해 당 텍스트를 넣어둘 텍스트 버퍼 변수를 준비해둬야 한다.

7) 텍스트 요소를 발견하면 무엇을 할 것인가? foundCharacters
텍스트 요소는 string에 문자열 형태로 들어온다. 하지만 텍스트 요소는 반드시 한 번에 전부 읽힌다는 보 장이 없고, 몇 번으로 나뉘어 읽히기도 한다. 이 때문에 연속해서 텍스트 요소를 발견하면 그때마다 문자 열을 이어야 한다.

8) 종료 태그를 발견하면 무엇을 할 것인가? didEndElement
종료 태그를 발견하면 지금까지 읽어들인 텍스트 요소가 확정되었다는 의미가 된다.

9) 해석을 종료하면 무엇을 할 것인가? parserDidEndDocument 해석 종료 시에 처리가 필요하면 여기서 실행한다. 


- 화면 디자인

- NSXMLParser 예제 순 서

1. Xcode 실행

2. Single View Application
3. Project Name : “XMLTest”
4. storyboard에 Text View 위치
5. Assistant Editor로 Text View 드래그

6. “myTextView” 입력
7. ViewController.h 파일 편집

8. ViewController.h 파일 편집

@interface ViewController : UIViewController <NSXMLParserDelegate> { NSString *nowTagStr;

NSString *txtBuffer;

}
@property (weak, nonatomic) IBOutlet UITextView *myTextView; @end

- (void)viewDidLoad
{ [super viewDidLoad];

// 텍스트 뷰를 초기화 시키고 편집불가로 설정 myTextView.text = @"";

myTextView.editable = NO;
// URL을 지정해서 XML서버를 작성한다.

NSURL *myURL = [NSURL URLWithString:@"http://www.ymori.com/itest/test.xml"]; NSXMLParser *myParser = [[NSXMLParser alloc] initWithContentsOfURL:myURL]; myParser.delegate = self;
// 해석을 개시한다.

[myParser parse];

}
- (void)parserDidStartDocument:(NSXMLParser *)parser {

// 해석중인 태그를 초기화한다.
nowTagStr = [NSString stringWithString:@""];

}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName

namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
// 개시 태그가 "sweets"이면
if([elementName isEqualToString:@"sweets"]) {

} }

// 해석중인 태그로 설정
nowTagStr = [NSString stringWithString:elementName]; // 텍스트 버퍼를 초기화시킨다.
txtBuffer = [NSString stringWithString:@""];

// 텍스트 뷰에 태그 명과 price속성을 추가한다.
myTextView.text = [myTextView.text stringByAppendingFormat:

@"태그 명=[%@]\n 속성 price=[%@]",
elementName, [attributeDict objectForKey:@"price"]];

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { // 해석중인 태그가 "sweets"이면

if ([nowTagStr isEqualToString:@"sweets"]) {
// 텍스트 버퍼에 문자열을 추가한다.

txtBuffer = [txtBuffer stringByAppendingString:string];

} }

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {

// 종료태그가 "sweets"이면
if ([elementName isEqualToString:@"sweets"]) {

} }

- (void)viewDidUnload {

// 텍스트 뷰에 텍스트 버퍼의 문자열을 추가한다.
myTextView.text = [myTextView.text stringByAppendingFormat:

@"\n 요소=[%@]\n\n",txtBuffer];

[self setMyTextView:nil];
[super viewDidUnload];
// Release any retained subviews of the main view. // e.g. self.myOutlet = nil;

}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // Return YES for supported orientations

return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown); }

@end

일반적으로 프로그램에서 XML을 읽어들이면 자동으로 계층 구조까지 해석해주지만, NSXMLParser를 이 용할 때는 내용을 직접 해석해야 한다. 일반적인 전자동 해석 방법은 편리하기는 하지만 메모리 사용량이 많아지거나, 처리 내용이 많아져서 속도가 느려지는 등 하드웨어에 부담을 준다. 이 때문에 아이폰에서 NSXMLParser를 사용한다고 생각한다. 


- ViewController.m 소스코드

#import "ViewController.h"


@interface ViewController ()


@end


@implementation ViewController

@synthesize myTextView;


- (void)viewDidLoad

{

    [super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

myTextView.text = @"";

myTextView.editable = NO;

NSURL *myURL = [NSURL URLWithString:@"http://www.ymori.com/itest/test.xml"];

NSXMLParser *myParser = [[NSXMLParser alloc] initWithContentsOfURL:myURL];

myParser.delegate = self;

// 해석을 개시한다.

[myParser parse];

}


- (void)viewDidUnload

{

[self setMyTextView:nil];

    [super viewDidUnload];

    // Release any retained subviews of the main view.

}


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

{

if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {

    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);

} else {

    return YES;

}

}


-(void)parserDidEndDocument:(NSXMLParser *)parser{

//해석중인 태그를 초기화한다.

nowTagStr = [NSString stringWithFormat:@""];

}


-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{

// 개시 태그가 "sweets"이면

if([elementName isEqualToString:@"sweets"]){

//해석중인 태그로 설정

nowTagStr = [NSString stringWithString:elementName];

//텍스트 버퍼를 초기화시킨다.

txtButter = [NSString stringWithString:@""];

//텍스트 뷰에 태그 명과 price속성을 추가한다.

myTextView.text = [myTextView.text stringByAppendingFormat:   @"태그 =[%@]\n 속성 price=[%@] \n 요소 = [%@]",

elementName, [attributeDict 

objectForKey:@"price"]];

}

}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{

// 해석중인 태그가 "sweets" 이면

if ([nowTagStr isEqualToString:@"sweets"]) {

// 텍스트 버퍼에 문자열을 추가한다.

txtButter = [txtButter stringByAppendingFormat:string];

}

}

-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{

// 종료태그가 "sweets"이면

if([elementName isEqualToString:@"sweets"]){

// 텍스트 뷰에 텍스트 버퍼의 문자열을 추가한다.

myTextView.text = [myTextView.text stringByAppendingFormat:

  @"\n 요소=[%@]\n\n",txtButter];

}

}


@end


- 실행화면

신고
Posted by Namseungil
JAVA/Android2012.03.13 12:34

- 안드로이드에서 파싱 기술을 이용해서, 트위터 앱을 만들어 보자.
- XmlPullParser를 이용해, 트위터를 파싱하는 예제이다.

- Java 소스

public class Ex13_TwitterClientActivity extends Activity implements
  OnClickListener {
 static int ITEMCOUNT = 5;
 ArrayList<MyItem> mItems;
 CustomAdater mAdapter;
 String mName;

 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);

  mItems = new ArrayList<MyItem>();

  mAdapter = new CustomAdater(this, R.layout.item, mItems);

  ListView list = (ListView) this.findViewById(R.id.list);
  list.setAdapter(mAdapter);

  Button btn = (Button) this.findViewById(R.id.button1);
  btn.setOnClickListener(this);

 }

 @Override
 public void onClick(View arg0) {
  // TODO Auto-generated method stub
  switch (arg0.getId()) {
  case R.id.button1:
   EditText edit = (EditText) this.findViewById(R.id.editname);
   mName = edit.getText().toString();
   if (mName != null) {
    mItems.clear();
    String url = "http://twitter.com/statuses/user_timeline.xml?screen_name="
      + mName + "&count=" + ITEMCOUNT;

    // http://twitter.com/statuses/user_timeline.xml?screen_name=oisoo&count=5"
    String xml = downloadURL(url);
    parseXML(xml);
    mAdapter.notifyDataSetChanged();
   }

   break;

  }

 }

 void parseXML(String xml) {
  int itemtype = 0;
  //int itemtype2=0;
  String itemText = "";
  // MyItem temp = new MyItem();
  String tempicon = "", tempscreen = "", tempname = "", temptext = "", temptime = "";

  try {
   XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
   XmlPullParser parser = factory.newPullParser();
   parser.setInput(new StringReader(xml));
   // 여기까지 의미있는부분을 짤라준다.
   int eventType = parser.getEventType();
   while (eventType != XmlPullParser.END_DOCUMENT) {
    switch (eventType) {
    case XmlPullParser.START_DOCUMENT:
     break;
    case XmlPullParser.END_DOCUMENT:
     break;
    case XmlPullParser.START_TAG:
     if (parser.getName().equals("profile_image_url"))itemtype = 1;
     if (parser.getName().equals("screen_name"))itemtype = 2;
     if (parser.getName().equals("name"))itemtype = 3;
     if (parser.getName().equals("text"))itemtype = 4;
     if (parser.getName().equals("created_at"))itemtype = 5;
     break;
    case XmlPullParser.END_TAG:
     if (parser.getName().equals("status")) {
      // mItems.add(new MyItem(temp));
      mItems.add(new MyItem(tempicon, tempscreen, tempname,
        temptext, temptime));
     }
     break;
    case XmlPullParser.TEXT:
     if (itemtype == 1) tempicon = parser.getText();
     if (itemtype == 2) tempscreen = parser.getText();
     if (itemtype == 3) tempname = parser.getText();
     if (itemtype == 4) temptext = parser.getText();
     if (itemtype == 5) temptime = parser.getText();
     
     itemtype = 0;
     break;
    }
    eventType = parser.next();
   }
  }
  catch (Exception e) {
   
  }
  // TextView text1 = (TextView)this.findViewById(R.id.tv1);
  // text1.setText(itemText);

 }

 String downloadURL(String addr) {
  String doc = "";
  try {
   URL url = new URL(addr);
   HttpURLConnection conn = (HttpURLConnection) url.openConnection();

   if (conn != null) {
    conn.setConnectTimeout(10000);
    conn.setUseCaches(false);
    if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { // 연결이
                   // 완성이됫다
     BufferedReader br = new BufferedReader(
       new InputStreamReader(conn.getInputStream()));
     for (;;) {
      String line = br.readLine();
      if (line == null)
       break;
      doc = doc + line + "\n";
     }
     br.close();
    }
     conn.disconnect();
   }
  } catch (Exception ex) {
   ;
  }

  return doc;

 }
}
----------------------------------------------------------------------------------------------------------------

public class CustomAdater extends BaseAdapter {
 Context context;
 int itemlayout;
 ArrayList<MyItem> arrayItems;
 LayoutInflater inflater;
 public CustomAdater(Context c, int sublayout, ArrayList<MyItem> list){
  this.context=c;
  this.itemlayout=sublayout;
  this.arrayItems=list;
  
  inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 }
 @Override
 public int getCount() {
  // TODO Auto-generated method stub
  return arrayItems.size();
 }

 @Override
 public Object getItem(int position) {
  // TODO Auto-generated method stub
  return arrayItems.get(position);
 }

 @Override
 public long getItemId(int position) {
  // TODO Auto-generated method stub
  return position;
 }

 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  // TODO Auto-generated method stub
  final int pos = position;
  
  if(convertView == null){
   convertView = inflater.inflate(itemlayout, parent,false);
  }
  
  ImageView img = (ImageView)convertView.findViewById(R.id.image1);
  //img.setImageResource(arrayItems.get(position).image);
  //img.setImageResource(R.drawable.icon);//초기화
  try{
   InputStream is = new URL(arrayItems.get(position).icon).openStream();
   Bitmap bit = BitmapFactory.decodeStream(is); // Factory 비트맵 다운로드
   img.setImageBitmap(bit);
   is.close();
  }
  catch(Exception e){
   img.setImageResource(R.drawable.icon);
  }
  
  TextView text1 = (TextView)convertView.findViewById(R.id.text1);
  text1.setText(arrayItems.get(position).scrren+"  "+arrayItems.get(position).name);
  
  TextView text2 = (TextView)convertView.findViewById(R.id.text2);
  text2.setText(arrayItems.get(position).text);
  
  TextView text3 = (TextView)convertView.findViewById(R.id.text3);
  text3.setText(arrayItems.get(position).time);
      
  return convertView;
 }

}
----------------------------------------------------------------------------------------------------------------public class MyItem {
 String icon, scrren, name, text, time;

 public MyItem(String icon, String scrren, String name, String text,
   String time) {
  this.icon = icon;
  this.scrren = scrren;
  this.name = name;
  this.text = text;
  this.time = time;
 }

 MyItem(MyItem obj) {
  this.icon = obj.icon;
  this.scrren = obj.scrren;
  this.name = obj.name;
  this.text = obj.text;
  this.time = obj.time;
 }

 MyItem() {

 }

}
----------------------------------------------------------------------------------------------------------------
-xml 소스
<!--main.xml-->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="0"
        android:orientation="horizontal" >

        <EditText
            android:id="@+id/editname"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="0"
            android:text="load" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1"
        android:orientation="vertical" >

        <ListView
            android:id="@+id/list"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" >
        </ListView>
    </LinearLayout>

</LinearLayout>
----------------------------------------------------------------------------------------------------------------
<!--item.xml-->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal" >

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:layout_weight="0"
        android:orientation="vertical" >

        <ImageView
            android:id="@+id/image1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:layout_weight="1"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/text1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <TextView
            android:id="@+id/text2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="5" />

        <TextView
            android:id="@+id/text3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1" />
    </LinearLayout>

</LinearLayout>
----------------------------------------------------------------------------------------------------------------
-AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="Ex13_TwitterClient.org"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="7" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".Ex13_TwitterClientActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
     <uses-permission
    android:name="android.permission.INTERNET"/>
</manifest>
----------------------------------------------------------------------------------------------------------------- 실행 화면

신고
Posted by Namseungil
JAVA/Android2012.01.20 15:53

- 인터넷에 있는 자료를 나의 App에 가져와서 데이터를 내 것 처럼 사용하는 기술이 파싱이라고 한다. 이 파싱을 이용하는 간단한 예제를 해보자.
- 네이버 html, xml 소스를 띄어보고 트윗 tag를 짤라서 화면에 출력하는 간단한 예제이다.

- Java 소스
public class Ex13_HTTPActivity extends Activity implements OnClickListener {
 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);

  Button xml = (Button) this.findViewById(R.id.xml);
  xml.setOnClickListener(this);
  Button html = (Button) this.findViewById(R.id.html);
  html.setOnClickListener(this);
  Button parse = (Button) this.findViewById(R.id.parse);
  parse.setOnClickListener(this);
 }

 @Override
 public void onClick(View arg0) {
  // TODO Auto-generated method stub
  TextView text1 = (TextView) this.findViewById(R.id.tv1);
  switch (arg0.getId()) {

  case R.id.html:
   String html = downloadURL("http://www.naver.com");
   text1.setText(html);
   break;
  case R.id.xml:
   // String name = "oisoo";
   // int count = 2;
   String url1 = "http://www.naver.com";
   // ? 뒤에는 매개변수 & 추가적인 정보
   String xml1 = downloadURL(url1);
   text1.setText(xml1);

   break;
  case R.id.parse:

   String url = "http://twitter.com/statuses/user_timeline.xml?screen_name=oisoo&count=5";
   // ? 뒤에는 매개변수 & 추가적인 정보
   String xml = downloadURL(url);
   parseXML(xml);
   break;

  }

 }

 void parseXML(String xml) {
  int itemtype = 0;
  String itemText = "";

  try {
   XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
   XmlPullParser parser = factory.newPullParser();
   parser.setInput(new StringReader(xml));
   // 여기까지 의미있는부분을 짤라준다.
   int eventType = parser.getEventType();
   while (eventType != XmlPullParser.END_DOCUMENT) {
    switch (eventType) {
    case XmlPullParser.START_DOCUMENT:
     break;
    case XmlPullParser.END_DOCUMENT:
     break;
    case XmlPullParser.START_TAG:
     if (parser.getName().equals("text")) {
      itemtype = 1;
     }

    case XmlPullParser.END_TAG:
     break;
    case XmlPullParser.TEXT:
     if (itemtype == 1) {
      itemText = itemText + parser.getText() + "\n";
      itemtype = 0;
     }
     break;
    }
    eventType = parser.next();
   }
  } catch (Exception e) {
   ;
  }
  TextView text1 = (TextView) this.findViewById(R.id.tv1);
  text1.setText(itemText);

 }

 String downloadURL(String addr) {
  String doc = "";
  try {
   URL url = new URL(addr);
   HttpURLConnection conn = (HttpURLConnection) url.openConnection();

   if (conn != null) {
    conn.setConnectTimeout(10000);
    conn.setUseCaches(false);
    if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { // 연결이
                   // 완성이됫다
     BufferedReader br = new BufferedReader(
       new InputStreamReader(conn.getInputStream()));
     for (;;) {
      String line = br.readLine();
      if (line == null)
       break;
      doc = doc + line + "\n";
     }
     br.close();
    }
    // conn.disconnect();
   }
  } catch (Exception ex) {
   ;
  }

  return doc;

 }

}

-xml 소스
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="0"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/html"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="HTML" />

        <Button
            android:id="@+id/xml"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="XML" />

        <Button
            android:id="@+id/parse"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Parse XML" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1" >

        <TextView
            android:id="@+id/tv1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

</LinearLayout>

-실행 화면

신고
Posted by Namseungil

티스토리 툴바