|
namespace TestOpenApi { public partial class MainForm : Form { int detail_index; int naver_catagory=0; int daum_catagory=0; int select_engine=0;
public MainForm() { InitializeComponent(); Global gl = Global.GetInstance(); gl.DesignTable(); } … |
생성자에서 Document기능을 가진 Global 클래스의 인스턴스를 가져와 DesignTable메서드를 호출합니다
public void DesignTable() { BookDesignTable(); CommentDesignTable(); } … |
Global 클래스의 DesignTable에서는 책과 코멘트를 디자인하기위한 메서드를 호출합니다.
private void CommentDesignTable() { AddTitleColumn(dt2); AddSubColumn(dt2, "title", "System.String"); AddSubColumn(dt2, "comment", "System.String"); AddSubColumn(dt2, "text", "System.String");
dt2.WriteXmlSchema("commentschema.xsd"); }
private void BookDesignTable() { AddTitleColumn(dt); AddSubColumn(dt, "title", "System.String"); AddSubColumn(dt, "price", "System.Int32"); AddSubColumn(dt, "company", "System.String"); AddSubColumn(dt, "image", "System.String"); AddSubColumn(dt, "url", "System.String"); AddSubColumn(dt, "description", "System.String"); AddSubColumn(dt, "site", "System.String");
dt.WriteXmlSchema("bookschema.xsd"); } private DataColumn AddTitleColumn(DataTable dt) { DataColumn dc = new DataColumn(); dc.DataType = Type.GetType("System.Int32"); dc.AllowDBNull = false; dc.Caption = "num"; dc.ColumnName = "num"; dt.Columns.Add(dc); return dc; } private DataColumn AddSubColumn(DataTable dt, string header, string typename) { DataColumn dc = new DataColumn(); dc.DataType = Type.GetType(typename); dc.AllowDBNull = true; dc.Caption = header; dc.ColumnName = header; dt.Columns.Add(dc); return dc;
} … |
책의 테이블에는 검색번호, 책제목, 가격, 출판사, 이미지경로, 사이트 주소, 설명, 검색 엔진명을 속성으로 주었습니다.
코멘트의 테이블에는 검색번호, 책제목, 코멘트, 코멘트내용을 속성으로 주었습니다.
DataColumn의 AllowDBNull 속성에 false를 준 것은 null값을 허용 안하는 것이며 반대로 true는 null값을 허용하는 것입니다. Caption 속성은 외부로 보여주는 것이고 ColumnName은 데이터를 삽입할 때 사용 할 변수명입니다. Caption속성을 지정안해준 경우 ColumnName으로 설정됩니다.
도서 검색하기
private void button_search_Click(object sender, EventArgs e) { if (textBox_bname.Text != string.Empty) { Global gl = Global.GetInstance(); gl.ClearBook(); listView1.Items.Clear();
if (select_engine==0) { GetDaumXmlNode(); GetNaverXmlNode(); } if (select_engine==1) { GetNaverXmlNode(); } if (select_engine==2) { GetDaumXmlNode(); } AddBookList(gl.GetBooks()); } } |
도서명을 입력하는 textBox_bname 의 Text 속성값이 비어있지 않을 때만 검색하게 됩니다.
검색하기전 컨테이너에 보관중인 Book과 ListView에 저장되어있는 Book의 정보들을 초기화합니다. select_engine이 0일경우에는 Naver, Daum의 OpenAPI를 이용하여 검색하는 것이고, 1일 경우 Naver OpenAPI만, 2일 경우 Daum OpenAPI만 사용하여 검색합니다. 검색 후 에는 보관중인 책들을 ListView에 추가하여줍니다.
private void GetNaverXmlNode() { Global gl = Global.GetInstance(); gl.MakeNaverBooks(textBox_bname.Text, naver_catagory); }
private void GetDaumXmlNode() { Global gl = Global.GetInstance(); gl.MakeDaumBooks(textBox_bname.Text, daum_catagory); } ....
internal void MakeNaverBooks(string bookname, int naver_catagory) { XmlDocument doc = new XmlDocument();
if (naver_catagory == 0) { doc.Load(string.Format( "http://openapi.naver.com/search?key=af0afdce221cd09aa8d9790e2689e231&query={0}&display=10&start=1&target=book" , HttpUtility.UrlEncode(bookname, Encoding.GetEncoding("utf-8")))); } else { doc.Load(string.Format( "http://openapi.naver.com/search?key=af0afdce221cd09aa8d9790e2689e231& query={0}&display=10&start=1&target=book_adv&d_catg={1}&d_titl={0}", HttpUtility.UrlEncode(bookname, Encoding.GetEncoding("utf-8")), naver_catagory)); } XmlNodeList rssnode = doc.GetElementsByTagName("rss"); XmlNode channelnode = rssnode[0].SelectSingleNode("channel"); AddNaverBooks(channelnode); }
private void AddNaverBooks(XmlNode channelnode) { try { XmlNodeList items = channelnode.SelectNodes("item");
string title=string.Empty; int price=0; string company=string.Empty; string image=string.Empty; string link=string.Empty; string description=string.Empty;
foreach (XmlNode item in items) { XmlNode title_node = item.SelectSingleNode("title"); title = ConvertString(title_node.InnerText); XmlNode price_node = item.SelectSingleNode("price"); price = int.Parse(price_node.InnerText); XmlNode company_node = item.SelectSingleNode("publisher"); company = ConvertString(company_node.InnerText); XmlNode image_node = item.SelectSingleNode("image"); image = image_node.InnerText; XmlNode link_node = item.SelectSingleNode("link"); link = link_node.InnerText; XmlNode Description_node = item.SelectSingleNode("description"); description = ConvertString(Description_node.InnerText);
BookDirector bf = BookDirector.GetInstance(); books.Add(bf.MakeBook( title,price,company,image,link,description,BookDirector.Site.Naver)); }
} catch { } } |
naver_catagory와 daum_catagory은 0의 값이면 전체 카테고리의 검색입니다. OpenAPI를 제공하는 회사마다 스키마, 요청변수,catagory 번호 등등 다르므로 사이트를 참고 바랍니다.
Naver: http://dev.naver.com/openapi/apis/data/book
Daum : http://dna.daum.net/apis/search/book
|
Test를 통해 회사에서 제공해주는 Xml의 스키마를 확인 할 수 있습니다.
<rss> <channel> <item> <title></title> <link></link> ... </item> <item> <title></title> <link></link> ... </item>
</channel> </rss> |
Xml문서를 컨트롤 하기 위해 XmlDocument 개체를 하나 생성 후 Load메소드를 이용하여 회사에서 제공해준 Xml문서를 불러옵니다.
Naver에서는 보시다시피 rss 노드 1개, channel 노드 1개, item들의 노드는 여러개를 가지고 있습니다. rss노드를 얻어 온 후 그 노드를 이용해 channel 노드를 얻어 오고 , channel 노드를 이용해 item 노드들을 얻어와서 순서대로 item노드의 책의 정보를 얻어와 책을 생성합니다.
Builder 클래스
namespace TestOpenApi {
class BookDirector { List<IBookBuilder> builders = new List<IBookBuilder>(); public enum Site { Naver, Daum }
static BookDirector instance=null; static BookDirector() { instance = new BookDirector(); } private BookDirector() { builders.Add(new NaverBookBuilder()); builders.Add(new DaumBookBuilder()); } static public BookDirector GetInstance() { return instance; }
Book MakeBook(string title, int price, string company, string image, string link, string description, Site site) { if (site ==Site.Naver) { return builders[(int)site].MakeBook( title, price, company, image, link, description, "네이버"); } if (site== Site.Daum) { return builders[(int)site].MakeBook( title, price, company, image, link, description, "다음"); } return null;
} } } ...... public Book MakeBook(string bookname, int price, string company, string image_url, string url, string description, string site) { Book book = new Book(bookname); book.Price = price; book.Company = company; book.Image_url = image_url; book.Url = url; book.Description = description; book.Site = site; return book; } |
Book의 생성은 Build 패턴을 사용하였습니다. Naver와 Daum빌더에서는 각각 해당하는 Naver나 Daum의 책을 생성하여 return 합니다.
책의 정보 자세히보기
private void listView1_MouseDoubleClick(object sender, MouseEventArgs e) { Global gl = Global.GetInstance(); ListView ls = sender as ListView; if (ls != null) { tabControl1.SelectTab(1); DetailBookView(ls.FocusedItem.Index); } if (tabControl1.SelectedIndex == 0) { listView_comment.Clear(); tabControl1.SelectTab(0); } if (tabControl1.SelectedIndex == 1) { tabControl1.SelectTab(1); Book book = gl.GetBook(detail_index); ArrayList ar =book.GetComment();
int i = 0; for (i = 0; i < ar.Count; i++) { Comments comment = ar[i] as Comments;
ListViewItem lv = new ListViewItem(comment.Title); lv.ToolTipText = comment.Text;
listView_comment.Items.Add(lv); } } } ...
private void DetailBookView(int p) { detail_index = p; Global gl = Global.GetInstance(); Book book = gl.GetBook(p); label_bname.Text = book.Bname; label_company.Text = book.Company; label_price.Text = string.Format("{0}",book.Price); if (book.Image_url != string.Empty) { pictureBox_image_url.Load(book.Image_url); } textBox_description.Text = book.Description; } |
ListView에서 아이템을 더블클릭 시 해당 인덱스에 해당하는 책의 자세한 정보를 보기 탭에 띄워줍니다. DetailBookView에서는 해당 인덱스에 해당하는 책을 얻어와서 화면에 보여주고, 이미지는 PictureBox를 이용하여 불러옵니다.
자세히 보기 버튼을 클릭시
private void button_detailview_Click(object sender, EventArgs e) { ControlWeb cw = new ControlWeb(detail_index);
cw.ShowDialog(); } ...
namespace TestOpenApi { public partial class ControlWeb : Form { public ControlWeb(int index) { InitializeComponent();
Global gl = Global.GetInstance(); Book book = gl.GetBook(index); webBrowser1.Navigate(book.Url); } } }
|
자세히 보기 버튼 클릭시 ControlWeb 개체를 생성 합니다. 생성자 인자로는 현재 자세히 보고있는 책의 인덱스를 넘겨줍니다. ControlWeb 클래스에서는 해당 인덱스의 책을 얻어온 후 ControlWeb의 Navigate 메서드를 사용하여 해당 url을 보여줍니다.
책에 코멘트 달기
private void button2_Click(object sender, EventArgs e) {
if (textBox_title.Text != string.Empty) { if (textBox_text.Text != string.Empty) { Global gl = Global.GetInstance();
ListViewItem lv = new ListViewItem(textBox_title.Text); lv.ToolTipText = textBox_text.Text;
Book book = gl.GetBook(detail_index);
gl.AddComment(book.Bname, textBox_title.Text, textBox_text.Text); listView_comment.Items.Add(lv); MessageBox.Show("성공~!"); textBox_text.Text = string.Empty; textBox_title.Text = string.Empty; return;
} MessageBox.Show("내용을 입력하세요"); return; } MessageBox.Show("제목을 입력하세요");
} |
댓글 달기 버튼 클릭시 제목과 내용이 비어있지 않다면 Listview에 추가하게 되는데, 이때
ListviewItem의 속성 ToolTipText에 마우스가 over되면 보여주는 문자열을 대입하여, ListviewItem을 listview에 추가하여주면 툴팁이 완료 되었습니다. 코멘트에는 책의 이름과 코멘트제목, 코멘트 내용을 보관하여 줍니다.
검색 결과 저장하기
private void button_save_Click(object sender, EventArgs e) { Global gl = Global.GetInstance();
SaveFileDialog saveFileDialog = new SaveFileDialog(); saveFileDialog.Filter = "xml files (*.xml)|*.xml"; saveFileDialog.FilterIndex = 1; saveFileDialog.RestoreDirectory = true;
if (saveFileDialog.ShowDialog() == DialogResult.OK) { gl.Bnum = 0; gl.SaveBookData(saveFileDialog.FileName); } } |
검색결과 저장하기 버튼을 누르면 SaveFileDialog 클래스를 이용해 파일 대화상자를 이용해 저장위치와 이름을 입력 받아 Gloval클래스의 SaveBookData메서드에 파일 이름을 인자로 줍니다.
public void SaveBookData(string filename) { SaveBooks(); SaveBookTable(filename); } |
SaveBookData에서는 책들의 정보를 DataRow를 이용하여 DataTable에 저장하는 SaveBooks 메서드와 저장되있는 테이블 정보를 실제 파일로 쓰는 SaveBookTable 메서드를 호출합니다.
private void SaveBooks() { int i = 0; DataRow dr;
foreach(Book book in books) { dr = dt.NewRow(); dr["num"] = ++i; dr["title"] = book.Bname; dr["price"] = book.Price; dr["company"] = book.Company; dr["image"] = book.Image_url; dr["url"] = book.Url; dr["description"] = book.Description; dr["site"] = book.Site; dt.Rows.Add(dr); } } |
private void SaveBookTable(string filename) { dt.WriteXml(filename); } |
검색 결과 불러오기
private void button_load_Click(object sender, EventArgs e) { Global gl = Global.GetInstance();
OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.InitialDirectory = "c:\\"; openFileDialog1.Filter = "xml files (*.xml)|*.xml"; openFileDialog1.FilterIndex = 1; openFileDialog1.RestoreDirectory = true;
if (openFileDialog1.ShowDialog() == DialogResult.OK) { if ((openFileDialog1.OpenFile()) != null) { gl.Bnum = 0; listView1.Items.Clear(); gl.ClearBook(); gl.BookLoadData(openFileDialog1.FileName); AddBookList(gl.GetBooks()); } } } |
OpenFileDialog 클래스를 이용해 Load할 xml문서를 선택 한 후, Global 클래스의 BookLoadData 메서드를 호출합니다.
public void BookLoadData(string filename) { dt.ReadXmlSchema("bookschema.xsd"); dt.ReadXml(filename); SetBookData(); } |
BookLoadData에서는 초기에 저장된 bookschema의 스키마를 Read하고 xml문서를 read합니다.
private void SetBookData() { int count = dt.Columns.Count; Global gl = Global.GetInstance(); gl.ClearBook(); foreach (DataRow dr in dt.Rows) { SettingBookData(dr[1].ToString(), int.Parse(dr[2].ToString()), dr[3].ToString(), dr[4].ToString(), dr[5].ToString(), dr[6].ToString(),dr[7].ToString()); } } ... public void SettingBookData(string title, int price, string company, string image, string link, string description, string site) { BookDirector bd = BookDirector.GetInstance(); if (site == "다음") { books.Add(bd.MakeBook(title, price, company, image, link, description, BookDirector.Site.Daum)); } else { books.Add(bd.MakeBook(title, price, company, image, link, description, BookDirector.Site.Naver)); } } |
SetBookData에서는 데이터 테이블에 저장된 컬럼을 순서대로 얻어와 SettingBookData메서드를 호출하여 새로운 Book개체를 생성하여 보관합니다.
코멘트 저장하기
private void button_savecomment_Click(object sender, EventArgs e) { Global gl = Global.GetInstance();
SaveFileDialog saveFileDialog = new SaveFileDialog(); saveFileDialog.Filter = "xml files (*.xml)|*.xml"; saveFileDialog.FilterIndex = 1; saveFileDialog.RestoreDirectory = true;
if (saveFileDialog.ShowDialog() == DialogResult.OK) { gl.Bnum = 0; gl.SaveCommentData(saveFileDialog.FileName); } } |
검색결과 저장하기와 마찬가지로 파일쓰기 대화상자를 이용하여 저장할 xml 파일의 경로를 얻어온 후 SaveCommentData 메서드에 인자로 넣어줍니다.
public void SaveCommentData(string filename) { SaveComment(); SaveCommentTable(filename); } private void SaveComment() { DataRow dr; int i = 0; foreach (Book book in books) { foreach (Comments comment in book.GetComment()) { dr = dt2.NewRow(); dr["num"] = ++i; dr["title"] = comment.Bname; dr["comment"] = comment.Title; dr["text"] = comment.Text; dt2.Rows.Add(dr); } } } private void SaveCommentTable(string filename) { dt2.WriteXml(filename); } |
검색결과 저장하기와 동일합니다.
코멘트 불러오기
private void button_loadcomment_Click(object sender, EventArgs e) { Global gl = Global.GetInstance();
OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.Filter = "xml files (*.xml)|*.xml"; openFileDialog1.FilterIndex = 1; openFileDialog1.RestoreDirectory = true;
if (openFileDialog1.ShowDialog() == DialogResult.OK) { if ((openFileDialog1.OpenFile()) != null) { gl.Bnum = 0; gl.CommentLoadData(openFileDialog1.FileName);
} } } |
코멘트 불러오기 버튼을 눌르면 검색결과 불러오기와 마찬가지로 파일열기 대화상자를 이용하여 파일의 경로를 얻어와 CommentLoadData 메서드를 호출합니다.
public void CommentLoadData(string filename) { dt2.ReadXmlSchema("commentschema.xsd"); dt2.ReadXml(filename); SetCommentData(); } private void SetCommentData() { foreach (DataRow dr in dt2.Rows) { AddComment(dr[1].ToString(), dr[2].ToString(), dr[3].ToString()); } } public void AddComment(string bookname, string comment_title, string comment_text) { foreach (Book book in books) { if (book.Bname == bookname) { book.AddComment(bookname, comment_title, comment_text); return; } } } |
책의 이름을 검사해 같은 이름의 책에 보관하여 줍니다.
[21기 김동영]OpenAPI,XML.NET 도서검색프로그램.docx
|