XSL 스타일시트의 "match"와 "select" 속성 표현은 XML Path 언어 또는 XPath를 사용한다. Xpath 표현은 DOM 문서 트리의 노드 집합에 관해 설명한다. Xpath는 효과적인 XSLT 스타일시트를 작성하기 위한 강력한 표현 언어라고 할 수 있다.
Xpath로 다양한 구현이 가능한데, 그 중 네 가지는 다음과 같다.
Jaxen이라고 불리는 휴대용 Xpath 구현은 오픈소스이며 빠르다. 썬은 JavaServer Pages Standard Tag Library (JSTL)와 Java Web Services Developer Pack에 이를 포함시켰다.
- J2SE 1.5 (현재 Beta 2 출시)는 DOM 노드 검색 Xpath를 실행하는 새로운 Xpath 클래스를 제공한다. 이 새로운 인터페이스는 XML Processing (JAXP) 1.3, (JSR 206)를 위한 Java API에 포함되어있다.
(http://java.sun.com/j2se/1.5.0/docs/api ··· ath.html)
- JDOM과 dom4j 모두 Xpath 인터페이스를 제공한다.
(http://www.dom4j.org/apidocs/org/dom4j/ ··· ary.html)
(http://www.jdom.org/docs/apidocs/org/jd ··· ary.html)
- Apache의 Xalan 패키지에는 Xpath를 위한 패키지가 포함되어 있다. Xalan 패키지는 썬의 J2SE 런타임(
in rt.jar)에 포함되어 있으므로 그 디스트리뷰션을 구동할 때 Xalan의 XPath API를 사용할 수 있다. 그러나 J2EE 규격에서 Xalan이 모든 배포를 나타내도록 요구되지 않은 관계로 솔루션에는 휴대성이 없다.
(http://xml.apache.org/xalan-j/apidocs/o ··· ary.html)
이런 모든 옵션들은 휴대성이 있으며 경제적이다. 그러나 표준 J2EE 1.4 인스톨 시 언제나 위의 옵션들이 가능하다고 확신할 수는 없으며, 언제나 다른 회사의 라이브러리를 재분산할 수도 없을 것이다. 다행히, 위의 솔루션들을 사용하지 못한다 하더라도 Xpath 지원을 받을 수 있는 방법이 있다. 최신 J2EE 규격에 포함되어있는 TrAX (Transformation API for XML)를 사용하면 된다.
XPath 스타일시트
TrAX API는 XML을 변환하는 클래스의 인터페이스를 규정한다. API의 가장 일반적인 사용은 XSLT 스타일시트를 생성하고 사용하며 관리하는 것이다. XSLT 스타일시트를 생성하는 것은 2002년 10월 15일자 테크팁 Transforming XML With XSL(영문)에 나와있다. 또한 XSLT 스타일시트는 위의 팁 "기존 웹 리소스 사용하기"에서도 사용되었다.
TrAX Transformer는 XSLT 스타일시트의 Xpath 패턴을 Transformer의 입력문서와 매치시키기 위해 XPath matcher를 이용한다. Transformer의 XPath API 가 표준이 아닌 관계로 이에 접근할 수는 없지만, 원하는 패턴에 매치되는 스타일시트를 작성하고 매치되는 노드와 모든 하위 노드를 복사할 수 있다.
'code>/html/head/title' 패턴을 매치시킨다고 가정하자. 다음 예제에서의 XSLT 스타일시트는 그 Xpath 패턴을 매치시키고, 매치되는 노드와 모든 하위 노드를 결과로 복사한다.
<?xml version="1.0" encoding="utf-8"?>\n
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="no"/>
<xsl:template match="/html/head/title">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="*|@*|text()">
<xsl:apply-templates />
</xsl:template>
</xsl:stylesheet>
이 스타일시트는 두가지 템플릿을 갖고있다.
- 첫번째 템플릿은 요청된 Xpath와 매치되어 Xpath와 그의 하위 노드들을 모두 결과물에 복사한다. (
<xsl:copy-of select="."/>작용).
- 두번째 템플릿은 XSLT 디폴트 템플릿을 오버라이딩하여 첫번째 템플릿으로부터 도출된 데이터만을 마지막 결과에 표시한다. XSLT 템플릿의 디폴트가 모든 텍스트와 빈 공간 노드를 무시하지 않고 결과로 복사하기 때문에 이 템플릿은 필수적이다.
- 첫번째 템플릿의 패턴을 어떤 Xpath 패턴이던 이용해 교체할 수 있다. 교체 패턴에 매치되는 문서 안의 모든 노드가 결과로 도출될 것이다. 그러나 이 솔루션은 휴대성을 위해 퍼포먼스를 교체한 것이라는 사실을 잊지 말기 바란다. 이 Xpath 스타일시트 접근에는 몇가지 단점이 있는데, 스타일시트는 추가적인 프로세싱을 전개한다는 단점이 있으며, 전체 문서를 DOM 트리로 로딩하기 때문에 대형 문서에는 적절하지 않다. 또한 원래의 DOM으로부터 노드의 복사물을 리턴하기 때문에 Xpath 검색 결과를 원래의 트리를 편집하는 데 사용할 수 없다. 그러나 퍼포먼스가 중요하지 않다거나, 다른 솔루션을 사용할 수 없을 때 이 테크팁은 휴대할 수 있는 표준 기반 대안를 제공한다.
- 이번 팁의 샘플코드는 첫번째 템플릿의 "match" 속성과 같은 사용자정의 Xpath 표현으로 위와 같은 스타일시트를 생성한다. 그 후 스타일시트를
NodeList결과를 생성하는 입력문서에 컴파일하여 실행한다.
샘플 코드
샘플 코드의 TrAXPath 클래스의 메인 메서드는 적어도 두가지 인수를 필요로 한다.
- XML을 변환하기 위한 소스 ; 문서이름이나 URL
- 소스 XML에 적용할 한가지 이상의 Xpath 패턴
메인 메서드는 입력XML을 DOM으로 파싱한 후 각각의 Xpath 표현에 대한 TrAXPath 오브젝트를 생성하고, 표현에 매치되는 노드들의 리스트를 생성하는데 그 오브젝트를 이용한다. 마지막으로 매치되는 노드들을 출력한다.
// Match xpath against document
TrAXPath txp = new TrAXPath(xpath);
NodeList matched = txp.selectNodeList(doc);
// Summarize nodes
p("Match[" + xpath + "]");
for (int q = 0; q < matched.getLength(); q++) {
p("--------------------[" + q + "]--------------------");
printDOM(matched.item(q));
p("");
}
(p is a convenience method for System.out.println.)
다중 XML 문서가 매치될 수 있는 것과 비교하여 TrAXPath 클래스는 단일 XPath 표현을 나타낸다. selectNodeList(Node)에 대한 각각의 호출은 TrAXPath 오브젝트 안의 XPath 표현에 매치되는 Nodes의 리스트를 리턴한다.
TrAXPath 오브젝트는 XPath를 포함하고 있는 String으로 구성된다. 구성자는 메모리에 XSLT 스타일시트를 구축하고 이를 Templates오브젝트로 컴파일한다.
public TrAXPath(String xpath)
throws TransformerConfigurationException {
StringBuffer sb = new StringBuffer();
// Create stylesheet that copies matching nodes
sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
sb.append("<xsl:stylesheet version=\"1.0\" ");
sb.append
(" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">");
sb.append("<xsl:output method=\"xml\" indent=\"no\"/>");
sb.append("<xsl:template match=\"" + xpath + "\">");
sb.append("<xsl:copy-of select=\".\"/>");
sb.append("</xsl:template>");
sb.append("<xsl:template match=\"*|@*|text()\">");
sb.append("<xsl:apply-templates />");
sb.append("</xsl:template>");
sb.append("</xsl:stylesheet>");
// Construct the stylesheet Templates object.
TransformerFactory tf = TransformerFactory.newInstance();
String stylesheet = sb.toString();
Reader r = new StringReader(stylesheet);
StreamSource ssrc = new StreamSource(r);
// Create templates object
_templates = tf.newTemplates(ssrc);
}
변환작업을 실행하는 Transformer를 생성하기 위해 TransformerFactory를 사용하는 것에 아마도 익숙할 것이다. 한편, javax.xml.transform.Templates 오브젝트를 생성하기 위해서도 이 TransformerFactory를 사용할 수 있다. 스타일시트를 한 번 이상 사용한다면 Templates 오브젝트를 이용해 Transformer를 생성하는 것도 좋은 방법이다. 이 때 스타일시트는 한번만 컴파일하면 된다.
TrAXPath 클래스에서 실제작업은 메서드 c에서 이뤄진다. 메인 메서드는 패턴과 XML 입력물을 매치시키기 위해 selectNodeList를 이용한다. selectNodeList 메서드는 Transformer를 생성하기 위해 _templates 오브젝트를 사용한다.
// Return a Node that matches xpath in context.
public NodeList selectNodeList(final Node context)
throws TransformerConfigurationException,
ParserConfigurationException,
TransformerException {
Transformer t = _templates.newTransformer();
그리고 이 메서드는 단일 DocumentFragment 를 포함하는 DOMResult(transformer의 결과로써 필요)를 생성한다.
// Create result document with top element "result"
DocumentFragment df = DocumentBuilderFactory.
newInstance().
newDocumentBuilder().
newDocument().
createDocumentFragment();
Result result = new DOMResult(df);
TrAXPath 코드는 Document대신 DocumentFragment를 사용하는데, 이는 결과물이 노드들의 리스트로 나타나야 하기 때문이다. Document는 최상의 노드 하나만을 도출할 뿐이며 빈 문서를 Transformer에 전달하면 오류가 발생되며 하나 이상의 Node가 생기는데, DocumentFragment에는 이러한 제한이 없다.
마지막으로 selectNode 메서드는 메모리 안의 스타일시트를 이용해 생성된 Transformer로 Node소스(검색된 Node)를 변환한다. Transformer는 DocumentFragment에 매치되는 XPath를 모두 복사한다. DocumentFragment's getChildNodes메서드를 호출하면 XPath 표현에 매치되는 모든 node들의 NodeList을 리턴한다.
// Transform result into DocumentFragment
t.transform(new DOMSource(context), result);
// Return list of nodes in DocumentFragment
return df.getChildNodes();
}
코드 실험
애플리케이션 index.html 페이지의 두번째 형식은 서블렛에 전달되어 입력한 XPaths에 대한 빌트인 XML 파일(여기서는 셰익스피어의 첫번째 연극 "A Comedy of Errors")을 검색한다.
예를 들어 입력파일에서 연극의 제목을 검색하려면 검색창에서 "/PLAY/TITLE" 라고 XPath식을 입력하고 Search를 클릭한다. 그러면 서블렛이 다음의 결과를 도출한다.
<?xml version="1.0" encoding="UTF-8"?> <TITLE>The Comedy of Errors</TITLE>
"/"로 검색하면 문서의 맨 위 노드에 매치되는 전체 파일을 볼 수 있다.
독자적인 메인 메서드를 보유한 TrAXPath 클래스를 다운로드 할 수도 있다. 형식의 다운로드 링크를 클릭하여 클래스 파일을 다운로드한 후 현재 디렉토리에 저장하자. 현재 디렉토리는 CLASSPATH에 있어야 한다. 그러면 다음과 같이 어떤 XML 파일에도 XPath식을 실행할 수 있다.
$ java com.elucify.tips.jul2004.TrAXPath xmlsource xpath
매개변수 xmlsource는 로컬 파일시스템의 이름이거나 XML 파일의 URL 일 수 있다.
다음의 샘플 XML을 보자.
<a>
<b>This is /a/b</b>
<c>
<b>This is /a/c/b</b>
</c>
<d>
<b>This is /a/d/b (first)</b>
<b>This is /a/d/b (second)</b>
</d>
<e>
<b>
<b>This is /a/e/b/b. What will happen?</b>
</b>
</e>
</a>
XML 트리에 대해 TrAXPath 프로그램을 구동시키고 "//b" 패턴을 검색하면("b" 는 트리 안의 아무 곳이나 의미), 다음의 결과를 도출한다.
Match[//b]
--------------------[0]--------------------
<?xml version="1.0" encoding="UTF-8"?>
<b>This is /a/b</b>
--------------------[1]--------------------
<?xml version="1.0" encoding="UTF-8"?>
<b>This is /a/c/b</b>
--------------------[2]--------------------
<?xml version="1.0" encoding="UTF-8"?>
<b>This is /a/d/b (first)</b>
--------------------[3]--------------------
<?xml version="1.0" encoding="UTF-8"?>
<b>This is /a/d/b (second)</b>
--------------------[4]--------------------
<?xml version="1.0" encoding="UTF-8"?>
<b>
<b>This is /a/e/b/b. What will happen?</b>
</b>
Matcher가 모든 b노드들을 매치시켰는지 확인해보자. match 4에서 다른<b> 노드 안의 <b>노드는 왜 매치시키지 않았을까?
첫번째 템플릿의 작용 때문에 matcher 는 다른 <b>안의 <b>를 찾지 않았다. <b>를 매치하자마자 matcher는 노드와 그 노드의 하위노드를 출력값으로 복사한다. 그러나 그 때 하위노드를 체크하지는 않는 것이다. 따라서 하위노드들을 matcher는 볼 수 없다.
다른 <b> 안에 있는 <b> 까지 모든 <b> 를 매치시키고 싶으면 첫번째 템플릿을 다음과 같이 약간 수정해야한다.
<xsl:template match="/html/head/title">
<xsl:copy-of select="."/>
<xsl:apply-templates select="./*"/>
</xsl:template>
새로운 규칙(apply-templates)은 스타일시트 프로세서가 현 노드의 모든 하위노드를 체크하고 프로세스하도록 명령한다. 아마도 애플리케이션 요구사항에 따라 이를 더 선호할 수 있다.
이 테크팁을 위한 샘플 코드는 XML 소스로 파일 대신 URL을 받아들인다. 이 때문에 TrAXPath 프로그램은 인터넷의 정크 데이터를 가려내는데 유용해진다. 예를 들어 RSS feed로 프로그램을 구동시킬 수 있다.
$ java com.elucify.tips.jul2004.TrAXPath \
http://servlet.java.sun.com/syndication/rss_java_highlights-10.xml \
'//item/title/text()'
Match[//item/title/text()]
--------------------[0]--------------------
<?xml version="1.0" encoding="UTF-8"?>
Java Live Chat: Java Web Services Developer Pack 1.4.
--------------------[1]--------------------
<?xml version="1.0" encoding="UTF-8"?>
The JVMPI Transition to JVMTI
--------------------[2]--------------------
<?xml version="1.0" encoding="UTF-8"?>
What's Next? A Conversation about Web Communication with
XML Pioneer, Tim Bray
--------------------[3]--------------------
<?xml version="1.0" encoding="UTF-8"?>
Upcoming Java Live Chat: Sun Game Server Technology.
--------------------[4]--------------------
<?xml version="1.0" encoding="UTF-8"?>
The Utility Model for Online Games: Part Two of a Conversation
--------------------[5]--------------------
<?xml version="1.0" encoding="UTF-8"?>
Get Ready for SOA
--------------------[6]--------------------
<?xml version="1.0" encoding="UTF-8"?>
2004 JavaOne: Nokia Platinum Session
--------------------[7]--------------------
<?xml version="1.0" encoding="UTF-8"?>
Deploying Web Services: Grid Computing
--------------------[8]--------------------
<?xml version="1.0" encoding="UTF-8"?>
The J2EE 1.4 SDK and Sun Java Application Server Platform Edition 8
--------------------[9]--------------------
<?xml version="1.0" encoding="UTF-8"?>
The Sun Java Desktop System, Release 2 Arrives
Java 1.5 XPath 클래스가 J2EE 표준이 되기 전까지는 휴대용 DOM 노드를 어드레스하는 데 이 트릭을 사용하기 바란다.
샘플 코드 구동
이번 테크팁의 샘플 아케이브를 다운로드하자. 애플리케이션의 컨텐츠 루트는 ttjul2004이다. 다운로드된 EAR 파일 역시 완성된 소스 코드를 샘플로 포함하고 있다.
deploytool 프로그램을 이용하여 J2EE Reference Implementation 의 애플리케이션 아케이브(ttjul2004.ear)를 디플로이할 수 있다.
$J2EE_HOME/deploytool -deploy ttjul2004.ear localhost
localhost를 서버가 인스톨되어있는 호스트의 이름과 교체해보자. 단일 머신의 표준 인스톨을 위한 hostname은 일반적으로 localhost이다. http://localhost:8000/ttjul2004에서 애플리케이션에 접근해볼 수 있다.
Reference Implementation 대신 J2EE-compliant 구현하기 위해 당신이 사용하고 있는 J2EE 제품의 디플로이먼트 툴을 사용하여 플랫폼의 애플리케이션을 디플로이해보기 바란다.
See the index.jsp welcome file for instructions on running the application.
"Java EE" 카테고리의 다른 글
- Attach API (댓글 18개 / 트랙백 1개) 2007/09/03
- JSP 2.0 EXPRESSION LANGUAGE (댓글 1개 / 트랙백 0개) 2004/02/05
- 환경 엔트리를 이용해서 배포의 사용자 정의하기 (댓글 2개 / 트랙백 0개) 2003/12/24
- JAX-WS를 이용한 웹 서비스 개발 (댓글 1개 / 트랙백 0개) 2006/01/18
- EJB 2.1로 메시지 구동 빈 이용하기 (댓글 1개 / 트랙백 0개) 2005/05/18
- EclipseLink를 사용하여 JPA에서 반복 불가능한 읽기 방지 (댓글 0개 / 트랙백 1개) 2008/07/09
- 컴포넌트 시스템과 클래스 로더 경계 (댓글 1개 / 트랙백 0개) 2004/10/05
- JAX-WS Dispatch 및 Provider API를 이용한 문서 처리 (댓글 4개 / 트랙백 0개) 2006/09/15
- POJO를 Persistent Entity로 변환하기 (댓글 1개 / 트랙백 0개) 2005/12/27
- SAAJ 소개 (댓글 1개 / 트랙백 0개) 2005/06/08
댓글을 달아 주세요
늘 좋은 정보 감사합니다
2007/09/07 20:21좋은 정보 감사해요~
2007/09/19 05:42