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
=====================