Java
Java XML startElement(), characters(), endElement()
승모근뭉치
2023. 1. 12. 16:34
프로젝트 내 src 내 xml 패키지 내 test02.dtd
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT 도서리스트 (책)* >
<!ELEMENT 책 (제목, 저자, 출판사, 가격, 이미지?, 소개?)> <!-- ?는 zero 나 one -->
<!ELEMENT 제목 (#PCDATA)>
<!ELEMENT 저자 (#PCDATA)>
<!ELEMENT 출판사 (#PCDATA)>
<!ELEMENT 가격 (#PCDATA)>
<!ELEMENT 이미지 EMPTY>
<!ELEMENT 소개 (#PCDATA)>
<!-- 속성 선언 -->
<!--
<!ATTLIST 책
id ID #IMPLIED
분류 CDATA #REQUIRED>
-->
<!-- 맨 마지막 XPath 검색예제용 -->
<!ATTLIST 책
분류 CDATA #REQUIRED
id CDATA #REQUIRED>
<!-- 요것은 생략이 가능하도록 IMPLIED로
경로를 나타내도록 src 추가 -->
<!ATTLIST 이미지
name ENTITY #IMPLIED
src CDATA #IMPLIED>
<!-- 이미지 이용하기때문에 노테이션 선언
헬퍼 프로그램은 익스플로러로 -->
<!NOTATION gif
PUBLIC "image/gif" "C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe">
<!NOTATION jpg
PUBLIC "image/jpg" "C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe">
<!-- 외부 언파스드 엔티티 선언 -->
<!-- 외부 언파스드 엔티티(이미지) 선언 NDATA는 노테이션의 데이타라는 말 -->
<!ENTITY b1_img SYSTEM "img1.gif" NDATA gif>
<!ENTITY b2_img SYSTEM "img2.jpg" NDATA jpg>
<!ENTITY b3_img SYSTEM "img3.jpg" NDATA jpg>
<!-- 외부 파스드 엔티티 선언 -->
<!-- XML 파서가 해석할 수 있는 그러한 데이타 텍스트 파일, 이미지는 해석 못한다
파스드 엔티티는 노테이션 선언과 다르게 따로 NDATA 같이 적어줄 필요가 없구 -->
<!ENTITY b1_intro SYSTEM "b1.txt">
<!ENTITY b2_intro SYSTEM "b2.txt">
<!ENTITY b3_intro SYSTEM "b3.txt">
프로젝트 내 src 내 xml 패키지 내 test02.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--test02.dtd 파일 쓴 후 -->
<!DOCTYPE 도서리스트 SYSTEM "test02.dtd"><!-- id="book1"는 필요가 없다 -->
<도서리스트>
<!-- 마지막 XPath 검색예제 이전것 -->
<!--<책 분류="컴퓨터">-->
<책 분류="컴퓨터" id="book1"><!-- id추가후 XPathTest.java로 가기 -->
<제목>JAVA 프로그래밍</제목>
<저자>김말똥</저자>
<출판사>아이티 출판</출판사>
<가격>20000</가격>
<이미지 name="b1_img" /><!-- test02.dtd에 데이타가 EMPTY로 선언되었으므로 암것도 안씀 -->
<소개>&b1_intro;</소개>
</책>
<!--<책 분류="소설">-->
<책 분류="소설" id="book2">
<제목>삼국지</제목>
<저자>이문열</저자>
<출판사>역사 출판</출판사>
<가격>15000</가격>
<이미지 name="b2_img"/>
<소개>&b2_intro;</소개>
</책>
<!--<책 분류="컴퓨터">-->
<책 분류="컴퓨터" id="book3">
<제목>C언어</제목>
<저자>강길동</저자>
<출판사>터보 출판사</출판사>
<가격>15000</가격>
<이미지 name="b3_img"/>
<소개>&b3_intro;</소개>
</책>
</도서리스트>
프로젝트 내 src 내 java_xml 패키지 내 SearchXML.java
package java_xml;
import java.util.Hashtable;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
//요클래스를 삭스파서에 등록해야 한다 SearchBook 클래스 만들기
public class SearchXML extends DefaultHandler {
//멤버 선언
private Hashtable hash;
private String objName, objValue; //찾고자 하는 엘리먼트 또는 속성
private boolean isBook, isTitle, isWriter, isPublish, isPrice; //책인지 아닌지 구분하기위해
//생성자
public SearchXML(String objName, String objValue) {
//검색 될 엘리먼트명 또는 속성명
this.objName = objName;
//검색 될 데이타 값, 즉 검색될 키워드
this.objValue = objValue;
//해시 테이블 객체선언
this.hash = new Hashtable();
}
//contentHandler에 정의되어 있는 startElement() 오버라이딩
public void startElement(String uri, String localName, String qName, Attributes attr) throws SAXException {
if(qName.equals("책")) {//책이라는 엘리먼트를 만났으면,첫번째 항목값이 책이면
isBook = true;
// 책의 분류라는 속성을 체크
String kindVal = attr.getValue("분류");
hash.put("분류", kindVal);
}else if(qName.equals("제목")) {
isTitle = true;
}else if(qName.equals("저자")) {
isWriter = true;
}else if(qName.equals("출판사")) {
isPublish = true;
}else if(qName.equals("가격")) {
isPrice = true;
}
}
//이벤트가 발생할 때 그 발생한 이벤트들을 모두 해시테이블에 저장하자
public void characters(char[] ch, int start, int length) throws SAXException {
String str = new String(ch, start, length).trim();
if(isTitle) {
hash.put("title", str);
//한번 읽어왔기때문에 isTitle에 다시 false를 준다
isTitle = false; //그래야 다음 타이틀을 읽을때 트루로 설정한다
} else if(isWriter) {
hash.put("writer", str);
isWriter = false;
} else if(isPublish) {
hash.put("publisher", str);
isPublish = false;
} else if(isPrice) {
hash.put("price", str);
isPrice = false;
}
}
public void endElement(String uri, String localName, String qName) throws SAXException {
if(qName.equals("책")) {
// 해당 속성부분을 처리
// 속성 검색에 대한 startElement에 속성부분을 처리해놨기때문에
if(objName.equals("분류")) {// Hash table 에서 얻어온 건 객체라 형변환
String kindVal = (String) hash.get("분류"); //참조변수만듦
//읽어온 내용 화면에 출력
if( kindVal.indexOf(objValue) != -1 ) showBookInfo(); //해당 찾고자하는 검색어와 같은지
} else if(objName.equals("제목")) {
//해시테이블로 부터 어떤 값을 가져오자
String title = (String) hash.get("title");
if(title.indexOf(objValue) != -1) showBookInfo();
} else if(objName.equals("저자")) {
String writer = (String) hash.get("writer");
if(writer.indexOf(objValue) != -1) showBookInfo();
} else if(objName.equals("출판사")) {
String publisher = (String) hash.get("publisher");
if(publisher.indexOf(objValue) != -1) showBookInfo();
}
//이벤트 처리가 끝나면 해시 테이블을 비워줘야
hash.clear();//이벤트가 발생할때마다 비워놓지 않으면 계속해서 테이블 쌓여
//문제가 발생할 수 있다
isBook = false;
}
}
public void showBookInfo() {
System.out.println("제목 : "+hash.get("title"));
System.out.println("저자 : "+hash.get("writer"));
System.out.println("출판사 : "+hash.get("publisher"));
System.out.println("가격 : "+hash.get("price"));
System.out.println("=====================");
}
public void warning(SAXParseException exception) throws SAXException {
throw new SAXException("경고 이벤트 처리");
}
public void error(SAXParseException exception) throws SAXException {
//유효성 검사 처리
System.out.println("DTD 구조 위배 됩니다.");// 현재 쓴것들엔 스키마 아닌 DTD 만 있죠
System.out.println("유효하지 않는 문서 입니다.");
throw new SAXException("error 이벤트 처리!!");
}
public void fatalError(SAXParseException exception) throws SAXException {
//권고안 위배
System.out.println("XML 권고안에 위배됩니다..");
System.out.println("Well-formed 문서가 아닙니다.");
throw new SAXException("fatal 이벤트 처리!!!");
}
}
프로젝트 내 src 내 java_xml 패키지 내 SearchBook.java
package java_xml;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
public class SearchBook {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
SAXParserFactory saxFac = SAXParserFactory.newInstance();
SAXParser parser = saxFac.newSAXParser();
System.out.println("====== 책 제목 검색 ======");
//SearchXML 객체를 하나 만들기
//default handler
//제목에 자바가 들어가는 책을 찾고자 한다
SearchXML dhandler = new SearchXML("제목", "JAVA"); //해당 컨텐트내용을 자바로 검색하겠다
parser.parse("src/xml/test02.xml", dhandler);
//SAX는 새롭게 파싱을 해줘야 해요. 속성을 출력하려면
System.out.println("====== 책 분류 검색 ======");
// dhandler = new SearchXML("분류", "소설");
dhandler = new SearchXML("분류", "컴퓨터");
parser.parse("src/xml/test02.xml", dhandler);
}
}
//xsl 변환기의 개념 XSLTransformation 언어로 작성된 문서이다
//xsl 변환기
//xsl 문서에 정의되어 있는 변환 내용을 바탕으로 소스 XML 문서를 변환하
//여 다양한 구조의 결과 XML 문서로 생성하는 프로그램
//변환기를 거치면 HTML이라던가 XML 등의 다른 파일로 바뀐다
//XML과 XSL이 변환기를 거쳐서 새로운 XML 등을 만든다
//메모리에 올라온 DOM Tree 구조를 파일로 바꿀 때 사용했던 변환기를 말한다.
//자바에서 이런 변환기를 어찌 생성하는가
//JAXP의 TrAX(Transformation API for XML)
//. javax.xml.transform
//. javax.xml.transform.dom 결과문서가 DOM Tree 일 경우 사용 패키지
//. javax.xml.transform.sax 삭스파서를 이용해 사용할 수 있는 패키지 -> 결과문서가 이벤트형식일 때 사용한다
//. javax.xml.transform.stream 문서형태가 파일이라든지 네트웤상에서 전송되는 비트형태라던지.할때 쓰는패키지
//변환기에서는 XSL 을 참고하여 XML 을 변환
//XSL 이 없는 경우 변환과정 생략하고 XML 문서를 잘게 쪼개서 DOM 객체 형태로 생성한다던지 출력스트림을 통해서 파일로 저장시킬수도 있다
//아님 네트웤상으로 연결을해서 어떤원격지컴퓨터에 XML 문서를 보낼 수도 있다.
//보통은 XML+XSL 혼합해서 변환기로 변환시킨다.
//네트웤상에서 XML을 가져올 수도 있고, 로컬피씨상 하드디스크에서도 XML 문서 가져올수도있다.
//XML 파일이 없는 경우에는 변환과정 생략하고 DOM으로 만들거나 DISK로 저장하거나 네트웤에서 비트로 보내거나 한다
//Xalan 변환기(XSL변환기)-TrAX인터페이스(JAXP에 포함되어있는 패키지)를 모두 구현한것
//따라서 Xalan 을 따로 설치할 필요가 없다는 거죠 기본적으로 많이 사용하는 Xalan
//변환 기능이 없는 XSL 변환기 생성(XSL문서가 없는때)
//TransformerFactory factory = TransformerFactory.newInstance();
//Transformer transformer = factory.newTransformer();
//변환 기능이 있는 XSL 변환기 생성
//TransformerFactory factory = TransformerFactory.newInstance();
//Source source = ~; //Source객체는 인터페이스이다
//XSL 문서의 정보를 Source 객체로 만드는 코드
//XSL 문서가 파일
SearchBook.java 를 실행하면 콘솔창에 다음과 같은 결과가 나온다.
====== 책 제목 검색 ======
제목 : JAVA 프로그래밍
저자 : 김말똥
출판사 : 아이티 출판
가격 : 20000
=====================
====== 책 분류 검색 ======
제목 : JAVA 프로그래밍
저자 : 김말똥
출판사 : 아이티 출판
가격 : 20000
=====================
제목 : C언어
저자 : 강길동
출판사 : 터보 출판사
가격 : 15000
=====================