XPath

Development/XML 2013. 2. 19. 17:47


XPath(XML Path Language)는 W3C의 표준으로 확장 생성 언어 문서의 구조를 통해 경로 위에 지정한 구문을 사용하여 항목을 배치하고 처리하는 방법을 기술하는 언어이다. XML 표현보다 더 쉽고 약어로 되어 있으며, XSL 변환(XSLT)과 XML 지시자 언어(XPointer)에 쓰이는 언어이다. XPath는 XML 문서의 노드를 정의하기 위하여 경로식을 사용하며, 수학 함수와 기타 확장 가능한 표현들이 있다.

[편집]

XML 예제 문서

<?xml version="1.0" encoding="utf-8"?>
<wikimedia>
  <projects>
    <project name="Wikipedia" launch="2001-01-05">
      <editions>
        <edition language="English">en.wikipedia.org</edition>
        <edition language="German">de.wikipedia.org</edition>
        <edition language="French">fr.wikipedia.org</edition>
        <edition language="Polish">pl.wikipedia.org</edition>
      </editions>
    </project>
    <project name="Wiktionary" launch="2002-12-12">
      <editions>
        <edition language="English">en.wiktionary.org</edition>
        <edition language="French">fr.wiktionary.org</edition>
        <edition language="Vietnamese">vi.wiktionary.org</edition>
        <edition language="Turkish">tr.wiktionary.org</edition>
      </editions>
    </project>
  </projects>
</wikimedia>

아래의 XPath 식은

/wikimedia/projects/project/@name

모든 project 요소의 name 속성을 선택하고, 아래의 XPath 식은

/wikimedia/projects/project/editions/edition[@language="English"]/text()

모든 영문 Wikimedia 프로젝트의 주소(language 속성이 English인 모든 edition 요소의 문자열)를 선택하고, 아래의 XPath 식은

/wikimedia/projects/project[@name="Wikipedia"]/editions/edition/text()

모든 위키백과의 주소(Wikipedia의 이름 특성을 가진 project 요소 아래에 존재하는 모든 edition 요소의 문자열)를 선택한다.

[편집]바깥 고리






XML 문서에 XPath 식을 적용한 이미지


XML Path Language ( XPath ; XML 경로 언어)는 마크 업 언어 XML 기반의 문서의 특정 부분을 지정하는 언어 구문이다. XPath 자체는 간결한 구문 (표현 언어)이며, XML 기반의 마크 업 언어가 아니다. 표준화 단체 W3C (World Wide Web Consortium)에서 개발되어 1999 년 11 월 16 일 XML Path Language (XPath) 1.0 XSL Transformations(XSLT) 1.0 동시에 권고안으로 공표 된 [1] [2] . XPath는 XSLT와 XSL-FO 함께 스타일 시트 기술 XSL 의 구성 요소로 자리 매김하고있다. 2007 년 1 월 23 일, W3C에서 XPath 1.0의 차기 버전이 제정되어 XPath 2.0 이 XSLT 2.0 동시에 권고했다. 또한 W3C는 XPath 2.0을 확장 한 기술로 XQuery 1.0을 개발하고 2007 년 1 월 23 일 XPath 2.0 / XSLT 2.0 권고안과 동시에 XQuery 1.0 권고했다.

XPath 1.0가 발표되면 XML 문서에 대한 간단한 쿼리 언어 로 빠르게 XML을 다루는 소프트웨어 개발자 ( 프로그래머 )에게 받아 갔다. 원래는 XPath의 개발은 XSL ( XSLT )와 XPointer 에 공통되는 구문과 행동 모델을 개발하는 것을 목표로하고 있었다. 실제로 XSLT는 XML 문서의 특정 부분을 지정하는 패턴을 XPath를 기반으로 구문으로 지정한다. 일반적으로 XSLT 처리 계의 구현 은 XPath 처리 계의 구현을 포함한다.

XPath 1.0은 2007 년에 번역 된 JIS X 4160으로 JIS 규격 화되어있다.

목차

  [ 숨기기 ] 

데이터 모델 편집 ]

XPath의 데이터 모델 은 XML 문서는 루트 노드를 정점으로하는 노드의 트리 구조 로 다음의 7 종류의 노드로 구성된 (참고 : XML ).

  • 루트 노드
  • 요소 노드
  • 텍스트 노드
  • 속성 노드
  • 네임 스페이스 노드
  • 처리 명령 노드
  • 코멘트 노드

위치 경로 편집 ]

XPath에서 가장 일반적인 식은 위치 경로이다. 위치 경로는 XML 문서의 노드 (현재 컨텍스트 노드)를 기준으로 다른 노드 또는 여러 노드 (노드 집합)이 지정된 (지정되는 노드가 0 개 또는 1 개도없는 경우도 있다).

위치 경로는 하나 이상의 위치 단계의 순서로 기술된다. 여러 위치 단계에서 위치 경로를 설명하는 경우, 각 위치 단계는 / 로 분리된다.

위치 단계 편집 ]

위치 경로를 구성하는 각 위치 단계는 다음 세 가지 요소로 구성된다.

위치 단계는 다음의 두 가지 구문을 사용하여 설명 할 수있다.

  • 하나는 # 생략 구문 이며, 간결하고 XPath 식을 읽기 쉽게 쓰고 쉽게 작성할 수있다. 직관적이고 많은 경우 친근한 캐릭터 라인과 구문 설명한다.
  • 다른 하나는 생략하지 # 전체 구문 이며, 생략 구문에 비해 기술이 중복이지만, 생략 구문 더 많은 옵션을 지정할 수 있으며 XPath 식을주의 깊게 읽을 때 생략 구문보다 설명으로 설명하는 것이 XPath 식의 정확한 이해에 도움이된다.

생략 구문 편집 ]

생략 구문은 간단한 구문이며, 자주 사용되는 많은 기본값을 사용 생략 위치 단계를 설명 할 수있다.

생략 구문을 사용하여 간단한 위치 경로에 대한 예를 나타낸다.

  • / A / B / C

이 예에서는 선두가 / 이다 절대 경로이며, 0 개 또는 1 개 또는 복수의 C 요소를 선택한다. 선택된 C 요소는 B 요소의 자식 요소 (child element)이며, 그 B 요소는 A 요소의 자식이며, A 요소는 XML 문서의 루트 요소이다.

XPath 구문은 URI (Uniform Resource Identifier) ​​구문이나 파일 경로 구문을 모방하여 설계되어있다.

생략 구문은 앞의 예보다 복잡한 식을 작성할 수있다. 그러나 전체 구문과 비교하면 기술 능력은 제한된다.

  • 기본 child 축 이외에도 몇 가지  ( attribute 축, descendant-or-self 축, self 축, parent 축)을 지정할 수있다.
  • 간명 노드 이름의 지정 이외의 노드 테스트 를 지정 할 수있다.
  • 어떤 위치 단계에 대괄호 [과]을 뒤에 붙여 조건 을 지정할 수있다.

조금 복잡한 위치 경로의 예를 나타낸다.

  • A / / B / * [1]

이 예는, 선두가 / 이없는 상대 경로이며 모든 이름 ( * ) 첫 번째 요소 ( [1] )을 선택한다. 선택된 "첫 번째 요소"는 B 요소의 자식 요소 ( / )이며, 그 B 요소는 A 요소의 직간접적인 자식 요소 (하위 요소, / / )이며, 그 A 요소는 현재 문맥 노드의 자식이다.

생략 구문 목록과 공식적인 정의는 후 # 전체 구문과 생략 구문의 대응 관계 의 절의.

전체 구문 편집 ]

전체 구문의 일반 식은 다음 형태가된다

  • / 축 :: 네임 스페이스 : 노드 테스트 [조건] / ~ ~

대상 # 생략 구문 절에 나와있는 두 가지 예를 생략하지 않는 완전한 구문으로 다시 작성하면 다음과 같다.

  • / child :: A / child :: B / child :: C
  • child :: A / descendant-or-self :: node () / child :: B / child :: * [1]

이렇게 전체 구문 설명 된 위치 경로의 각 위치 단계에서는

  •  를 child 나 descendant-or-self 과 같이 명시 적으로 지정한다.
  • 축 지정에 이어 :: 을 설명하고, 노드 테스트 를 A 와 node () , * 과 같이 기술한다.
  • 생략 구문과 마찬가지로 노드 테스트 지정 뒤에 대괄호 [과]을 뒤에 붙여 조건 을 지정할 수있다.

축 편집 ]

위치 단계 의 축 (axis)의 설명은 XML 문서의 트리 에서 방향을 지정한다. XPath 사양에서 정의 된 13 개의 축 ( # 전체 구문 )을 나타낸다.

child
컨텍스트 노드의 자식 노드
descendant
컨텍스트 노드의 하위 노드
parent
문맥 노드의 부모 노드
ancestor
문맥 노드의 조상 노드
following-sibling
컨텍스트 노드의 형제 노드 중 후방의 노드
preceding-sibling
컨텍스트 노드의 형제 노드 중 전방 노드
following
XML 문서의 문서 순서에서 컨텍스트 노드보다 뒤에있는 모든 노드
preceding
XML 문서의 문서 순서에서 컨텍스트 노드보다 전방에있는 모든 노드
attribute
컨텍스트 노드가 요소의 경우, 그 속성 노드
namespace
컨텍스트 노드가 요소의 경우 네임 스페이스 노드
self
컨텍스트 노드 자신
descendant-or-self
컨텍스트 노드 자신과 컨텍스트 노드의 하위 노드
ancestor-or-self
컨텍스트 노드 자신과 문맥 노드의 조상 노드

생략 구문 에서 attribute 축을 사용 예를 보여준다.

  • / / a / @ href

이 예제에서는 href 속성 노드 집합을 선택한다. 선택된 href 속성 노드는 XML 문서 중 하나 a 요소 노드에 속해있다.

self 축은 뒷부분 조건 에서 그 술어의 바로 앞에있는 노드 테스트에서 선택된 노드를 설명하는 데 사용된다. 예를 나타낸다.

  • h3 [. = '관련 항목']

이 예제에서는 현재 노드의 자식 노드이자 내용의 텍스트 '관련 항목' 을 가진 h3 요소가 선택된다.

노드 테스트 편집 ]

위치 단계 노드 테스트 (node ​​test) 식 또는 특정 노드 이름으로 설명된다. 예를 들어, 네임 스페이스 접두사 gs 가 정의 된 XML 문서에서 / / gs : enquiry 과 노드 테스트가 작성된 경우, gs 네임 스페이스 아래 enquiry 를 노드 이름으로하는 모든 노드의 집합이이 노드 테스트 지정의 대상이된다.

노드 테스트 형식을 나타내는 [3] .

이름
"네임 스페이스 접두사 : 이름"이라는 형식으로도 좋고, attribute 축과 namespace 축 이외의 축 경우 해당 이름을 가진 모든 요소 노드를 지정한다. attribute 축의 경우는 그 이름의 모든 속성 노드를 지정하고 namespace 축의 경우 네임 스페이스 노드를 지정한다.
text ()
모든 텍스트 (문자열) 노드를 지정한다. 예 : <k> 안녕하세요 </ k> 중 '안녕'
comment ()
모든 XML 주석 노드를 지정한다. 예 : <! - 댓글 ->
processing-instruction ()
모든 XML 처리 명령 노드를 지정한다. 예 : <? xsl-stylesheet href = "article.css"?> processing-instruction (처리 명령 대상)이라는 형식으로 작성도 가능하며,이 경우는 processing-instruction ( 'xsl-stylesheet') 와 작성 및 지정 대상이된다.
node ()
모든 노드를 지정한다.
*
기본 노드 형식의 모든 노드를 지정한다. 여기에서 기본 노드 형식은 attribute 축과 namespace 축 이외의 축 경우는 요소 노드를 의미하고 attribute 축의 경우는 속성 노드를 namespace 축의 경우 네임 스페이스 노드를 각각 의미한다.
네임 스페이스 접두사 : *
네임 스페이스 접두사가 나타내는 네임 스페이스에 속하는 모든 기본 노드 형식의 노드를 지정한다.

전체 구문과 생략 구문의 대응 관계 편집 ]

위치 단계 의 # 전체 구문 과 # 생략 구문 의 대응 관계를 다음 [1] [4] .

전체 구문생략 구문설명
child ::(생략 아무것도 쓰지 않는다)컨텍스트 노드의 자식 노드
attribute ::@컨텍스트 노드가 요소의 경우, 그 속성 노드
/ descendant-or-self :: node () // /컨텍스트 노드 자신과 컨텍스트 노드의 하위 노드
self :: node ().컨텍스트 노드 자신
parent :: node ()..문맥 노드의 부모 노드

조건 편집 ]

위치 단계 는 노드 테스트 뒤에 괄호로 묶을 술어 (predicate) 복잡한 식을 작성하여 노드 테스트에서 지정된 노드 집합을 제한 할 수있다. 노드 집합을 좁힐 필요가없는 경우, 조건은 기술하지 않는다.

간단한 예를 나타낸다.

  • / / a [@ href = 'help.php']

이 예에서는 [@ href = 'help.php'] 부분이 조건이다. 이 XPath 식은 href 속성을 가지고 있고 그 속성 값이 'help.php' 인 모든 a 요소 노드를 지정한다.

앞의 예에서는 술어의 수는 1 개 였지만, 위치 경로를 구성하는 위치 단계마다 여러 조건을 지정할 수있다. 즉, 검색 조건을 여러 거듭해 지정할 수있다. 지정할 수있는 조건의 수에는 제한이 없다.

술어는 그 술어를 포함 위치 단계의 컨텍스트를 변경할 수는 없다. 그 직전의 노드 테스트에서 지정된 노드 집합이 그 위치 단계의 문맥이며, 조건이 지정 됨으로써 컨텍스트가 변경 될 수는 없다.

복잡한 예를 나타낸다.

  • / / a [@ href = 'help.php'] [name (..) = 'div'] [.. / @ class = 'header'] / @ target

이 예는 a 요소의 target 속성 값을 지정한다. 그러나이 XPath 식의 첫 번째 위치 단계에는 3 개의 조건이 기술되어 있으며, a 요소 중

  • a 요소의 href 속성 값이 'help.php' 이며,
  • 한편, a 요소의 부모 요소 요소 이름이 div 이며,
  • 한편, 부모 요소 ( div )의 class 속성의 값이 'header' 이다,

a 요소 만 먼저 위치 단계의 지정 대상이된다. 결국 첫 번째 위치 단계에서 좁혀지고 지정 대상이 된 a 요소의 target 속성이 지정된다.

데이터 형식과 연산자, 함수 편집 ]

XPath 1.0에서 규정 된 형식 과 연산자 , 함수 를 설명한다.

데이터 형식은 다음 4 가지가 정의되어있다.

  • 노드 집합 (node​​-set; 정렬되지 않은 노드 집합)
  • 문자열 (string)
  • 숫자 (number; 부동 소수점 )
  • 논리 형 (boolean)

연산자는 다음과 같습니다.

  • "/"연산자 "/ /"연산자 (전제)
  • "|"연산자 : 두 노드 집합의 합집합 노드 집합을 반환
  • 논리 연산자 : "and" "or"- 논리 값을 반환
  • 산술 연산자 : "+" "-" "*" "div"( IEEE 754 기반 나눗셈) "mod"(나머지) - 숫자 (부동 소수점)을 반환
  • 비교 연산자 : "=", "! =", "<", ">", "<=", "> ="- 논리 값을 반환

함수에는 다음과 같은 것이있다.

  • 문자열 처리 함수 : concat (), substring (), contains (), starts-with () ends-with (), substring-before (), substring-after (), translate (), normalize-space ( ), string-length ()
  • 숫자를 다루는 함수 : sum (), round (), floor (), ceiling ()
  • 노드의 정보를 가져 오는 함수 : name () local-name (), namespace-uri ()
  • 처리의 컨텍스트에 대한 정보를 가져 오는 함수 : position (), last ()
  • 형식을 변환하는 함수 : string () number () boolean ()

비교적 자주 사용되는 함수는 다음 절 이후에 조금 선발한다. 완전한 정의는 W3C의 권고안 (일본어 번역) 를 참조하십시오.

XPath 식에서는 괄호 (와)로 묶어 그룹화하고 평가 순서를 명시 할 수있다.

술어 는 연산자를 사용한 식을 포함 할 수있다. 논리 식 (논리 값을 반환하는 식)은 and 연산자 및 or 연산자으로 연결하거나, not () 함수의 인수 할 수있다. 문자열 (string)에는 Unicode 문자를 포함 할 수있다. 조건 연산자를 사용 예를 보여준다.

  • / / item [@ price> = 2 * @ discount]

이 예제에서는 price 속성의 수치가 discount 특성 숫자의 2 배 이상이다 item 요소의 집합을 선택한다.

연산자 |는 술어 내부에서도 조건 외부에서도 노드 집합의 합을 구하기 위해 사용할 수있다. 술어 외부에서 | 연산자를 사용 예를 보여준다.

  • v [x or y] | w [z]

이 예에서는 하나의 노드 집합을 반환. 반환되는 노드 집합은 처리중인 컨텍스트에서 자식으로 x 요소 또는 y 요소를 갖는 v 요소의 집합와 자식으로 z 요소를 가진 w 요소의 집합의 합집합이다.

노드 집합 함수 편집 ]

Number position ()
평가의 문맥 노드의 위치를​​ 숫자로 반환 (형제 노드의 위치).
Number Count ( node-set )
인수 노드 집합 (또는 노드 집합을 반환하는 식)의 노드 수를 반환.
node-SET ID ( object )
인수 개체의 문자열 값을 ID 형식의 특성 값으로 갖는 노드 집합을 반환.
String name ( node-set? )
인수로 전달 된 노드 집합의 첫 번째 노드의 이름을 반환 (노드가 요소의 경우 요소 이름, 속성의 경우 속성 이름).

문자열 함수 편집 ]

String String ( object? )
XPath에 규정 된 4 가지 데이터 형식 을 인수로 취할 수 사양으로 정해진 변환 규칙에 따라 문자열로 변환한다. 인수로 XPath 식을 전달할 수있다.
Number String-length ( string? )
인수로 전달 된 문자열의 길이 (문자 수)를 돌려 준다.
String substring ( string, number, number? )
인수로 전달 된 문자열의 부분 문자열을 반환.
String concat ( string, string, string * )
인수로 전달 여러 문자열을 연결하여 돌려 준다.
boolean Contains ( string1, string2 )
인수의 문자열 string1 문자열 string2 가 포함 된 경우 true를 반환. 포함되지 않은 경우는 false를 돌려 준다.
String normalize-space ( string? )
인수의 문자열을 정상화 해 돌려 준다. 즉, 문자열의 앞뒤 공백을 제거하고, 제거 된 문자열에 연속 나타나는 공백을 하나의 공백으로 교체 한 문자열을 돌려 준다.

논리 함수 편집 ]

boolean not ( boolean )
인수 논리 값의 반대 값을 돌려 준다.

숫자 함수 편집 ]

Number sum ( node-set )
인수로 전달 된 노드 집합의 각 노드의 문자열 값을 사양으로 정해진 변환 규칙에 따라 숫자로 변환하여 합계 한 값을 돌려 준다.

예 편집 ]

다음 XML 문서에서 XPath를 예시하고 설명한다.

<? XML  version = "1.0"  encoding = "utf-8" ?> 
<document >
     <! - XML 문서 -> 
    <chapter  title = "제 1 장" > 
        <paragraph > 단락 </ paragraph >
         <paragraph > 다음 단락 </ paragraph >
         <paragraph > 또한 다음 단락 </ paragraph >
         <paragraph > 마지막 단락 </ paragraph >
     </ chapter >
     <chapter  title = "제 2 장" > 
        <paragraph > 단락 </ paragraph >
     </ chapter >
 </ document >
  • / document  : 루트 요소 document 를 선택한다.
  • / *  : 이름을 한정하지 않고 루트 요소를 선택한다. 이 경우 같은 document 가 선택된다 (XML 문서는 반드시 하나의 루트 요소를 갖는)
  • / document / chapter  : document 요소의 자식 인 모든 chapter 요소를 선택한다.
  • / document / chapter [1]  : document 요소의 자식 요소 중 첫 번째 chapter 요소를 선택한다.
  • / / paragraph  : 문서의 모든 paragraph 요소를 선택한다.
  • / / chapter [@ title = "제 1 장"] / paragraph  : title 속성의 값이 "제 1 장"이다 chapter 요소의 자식 인 모든 paragraph 요소를 선택한다.

XPath 2.0 편집 ]

서두에서 언급 한 바와 같이, XPath의 2007 년 3 월 현재의 최신 버전 XPath 2.0은 2007 년 1 월 23 일에 표준화 단체 W3C 에서 권고되었다. 또한 XPath 1.0은 1999 년 11 월 16 일 권고했다. XQuery 1.0 (권고 후보)는 XPath 2.0의 확장이다. 또한 XPath 2.0 XSLT 2.0에서도 채용되고있다.

XPath 2.0 사양은 1.0에 비해 대규모로되어 매우 많은 기능이 규정되어있다. 그 중 특히 중요한 변화는 다양한 데이터 형식 을 취급 할 수있게 된 것이다. XPath 2.0 스키마 언어 XML Schema 에서 규정 된 내장 원자 데이터 형식 및 스키마에 정의 된 사용자 정의 형식을 처리 할 수있다. 모든 값은 시퀀스로 취급된다. 하나의 문자열 값과 노드는 시퀀스에있는 요소 중 하나라고 평가된다. XPath 1.0 노드 집합은 XPath 2.0 어떠한 순서를 갖는 순서로 대체. 다양한 형식을 처리하기 위해 XPath 2.0 함수 및 연산자 가 크게 확장된다.

XPath 2.0은 XQuery 1.0의 부분 집합이다. XPath 2.0은 XQuery 1.0 구문의 경로 식을 구성한다. XQuery 1.0 FLWOR라는 식에서는 for 절 구성 요소가된다.

구현 편집 ]

Java 편집 ]

javax.xml.xpath [5] 패키지가, XPath 1.0 구현되어있다. XPathFactory.newInstance (). newXPath () 에서, XPath의 인스턴스를 만들 수,XPath.evaluate () 에서 XPath를 평가할 수있다.

JavaScript 편집 ]

HTML이 아닌 일반 XML 관해서는 XMLHttpRequest 를 사용하면 DOM 나무를 만들 수 있으며, 모두에 대해 XPath 사용할 수있다. Internet Explorer 의 경우,XMLDomNode.selectNodes () [6] 에서 XPath를 사용할 수있다. Internet Explorer 이외의 브라우저에서는, DOM Level 3 XPath 사양대로XPathEvaluator.evaluate () [7] 에서, XPath를 취급.

현재 브라우저 표준 XPath를 사용할 수 있지만, 2007 년 정도까지는, JavaScript에서 구현 한 XPath가 만들어져 있고, JavaScript-XPath [8] 과 Google AJAXSLT [9] 등이 XPath를 구현하고있다.

관련 항목 편집 ]

각주 편집 ]

도움말 ]
  1. b XPath 1.0 사양 (영어) - W3C (World Wide Web Consortium)
  2. ^ W3C의 XPath 1.0 작업 부회는 제임스 클라크 와 스티븐 디로즈가 공동으로 편집기를 맡았다. 또한 XSLT 1.0 작업 부회는 제임스 클라크 편집기를 맡았다.
  3. ^ (주) 일본 유니텍 외에 2001 년, p.66
  4. ^ (주) 일본 유니텍 외에 2001 년, p.67
  5. javax.xml.xpath (Java Platform SE 6)
  6. selectNodes Method
  7. evaluate - Document Object Model XPath
  8. JavaScript-XPath
  9. Google AJAXSLT







XQuery 는 정적 타이핑 기능 (구현 의존의 기능)와 XML 데이터 질의에 대한 쿼리 언어 이며, 튜링 완전 하게 기능적인 언어 이기도하다. XPath 의 목적이 나무의 절점을 가리키는 (주소)이다 반면 XQuery의 목적은 XML 데이터 소스에 대한 조회 기능을 제공하기위한 것이다.

관계 모델 ( 관계 데이터베이스 )의 관계 문의가 수학적 배경이있다 관계 대수 연산없고 관계 논리 연산에 따라 같이 XQuery 질의는 형식 의미론 을 부여하고있다.

XQuery는 Quilt 라는 언어를 기반으로 설계되어 있지만, 그 밖에도 XPath 1.0, SQL , XQL, OQL , XML-QL, ML 과 같은 언어의 영향을 받고있다. 2007 년 1 월 23 일 W3C 에서 표준화 작업이 종료 권고 ( Recommendation )이되었다.

목차

  [ 숨기기 ] 

XPath 1.0과 XQuery 1.0 (XPath 2.0) 편집 ]

XQuery 1.0은 XPath 2.0의 확장이다. XPath 2.0은 XQuery 1.0에서도 구문으로 정확하고 제대로 실행되는 식은 어느 언어에서도 같은 결과를 돌려 준다. 한편, XPath 1.0과 XQuery의 하위 집합 XPath 2.0은 기본적 성질에 차이가있다. XPath 1.0 질의 결과를 고유 한 노드 집합으로 정의되는 반면, XPath 2.0에서 질의 결과는 순서를 가지고 중복 값을 허용 시퀀스이다. 그러나 XPath 2.0은 XPath 1.0에 대한 호환성 모드가 옵션으로 존재하고이 옵션을 사용할 수있는 환경에서는 XPath 2.0은 XPath 1.0과 동일한 결과를 얻을 수있다.

관련 항목 편집 ]

외부 링크 편집 ]

관련 리소스 편집 ]






http://stackoverflow.com/questions/1006283/xpath-select-first-element-with-a-specific-attribute 


이번에 플젝을 하면서 xml을 읽어서 처리 할 부분이 있었습니다.
jdom을 사용했었는데, dom4j라는 것을 알게 되어서 한번 사용을 해보려고 합니다.
일단 간단한 사용 방법을 익히기 위해서 이것저것 해보겠습니다.

dom4j는 xpath의 사용이 예전 jdom에 비해서 많이 편해졌습니다.

일단 xpath의 간단한 가이드를 먼저 알아보겠습니다.

1. "/AAA"
root Element를 선택합니다.

<AAA>
 <BBB><BBB/>
 <CCC><CCC/>
 <DDD>
    <BBB/>
  <DDD/>
</AAA>

2. "/AAA/CCC"
root element AAA의 자식element 중 CCC를 모두 선택합니다.

     <AAA
          <BBB/> 
          <CCC/> 
          <BBB/> 
          <BBB/> 
          <DDD
               <BBB/> 
          </DDD
          <CCC/> 
     </AAA

3. "/AAA/DDD/BBB"
    root Element AAA의 자식element인 DDD의 자식element인 BBB를 모두 선택합니다.
 
    <AAA
          <BBB/> 
          <CCC/> 
          <BBB/> 
          <BBB/> 
          <DDD
               <BBB/> 
          </DDD
          <CCC/> 
     </AAA

4."//BBB"

element BBB를 모두 선택합니다.
     <AAA
          <BBB/> 
          <CCC/> 
          <BBB/> 
          <DDD
               <BBB/> 
          </DDD
          <CCC
               <DDD
                    <BBB/> 
                <BBB/> 
               </DDD
          </CCC
     </AAA

5."//DDD/BBB"
DDD의 자식element인 BBB를 모두 선택합니다.

    <AAA
          <BBB/> 
          <CCC/> 
          <BBB/> 
          <DDD
               <BBB/> 
          </DDD
          <CCC
               <DDD
                    <BBB/> 
                    <BBB/> 
               </DDD
          </CCC
     </AAA

더 자세한 내용은

http://www.zvon.org/xxl/XPathTutorial/Output/example1.html

이곳을 참조하세요.


출처 - http://devyongsik.tistory.com/172






3. XPath


3.1 XPath란 무엇인가 ?


 XPath is XML 문서의 부분을 정의하기 위한 W3C의 표준 문법 규약으로  XML 엘러먼트를 정의하기 위하여 path(경로)를 사용한다. XPath 는 표준함수의 라이브러리를 제공하며 XSLT의 주요 부분이나 XML로 쓰여지지 않았다. 즉, XPath는 XML 문서의 부분을 정의하기 위한 문법 규약(syntax rule) 의 집합으로써 XPath에 대한 지식이 없이는 XSLT 문서를 생성할  수 없다.  XPath는 XML 문서의 노드를 정의하기 위하여 경로식(path expression)을 사용하며 이러한 경로들은 우리가 파일 시스템에서 사용하였던 표현과 아주 유사하다. 


temp/xpath/sample.jsp

XPath 예

아래의 XML 문서를 보도록 하자.

<?xml version="1.0" encoding="EUC-KR"?>

<catalog>

<cd>

<title>San DoKaebi</title>

<artist>기둥SeulKiDoong</artist>

<country>Korea</country>

<company>Dongeui</company>

<price>8000</price>

<year>1992</year>

</cd>


<cd>

<title>Say Yes</title>

<artist>Chake&Aska</artist>

<country>Japan</country>

<company>Sony 레코드</company>

<price>12000</price>

<year>1992</year>

</cd>

<cd>

<title>Hound dog</title>

<artist>Elvis Presley</artist>

<country>USA</country>

<company>RCA</company>

<price>9000</price>

<year>1972</year>

</cd>

<cd>

<title>Still got the blues</title>

<artist>Gary Moore</artist>

<country>UK</country>

<company>Virgin records</company>

<price>10.20</price>

<year>1990</year>

</cd>

<cd>

<title>Romanza</title>

<artist>Andrea Bocelli</artist>

<country>EU</country>

<company>Polydor</company>

<price>15000</price>

<year>1996</year>

</cd>

<cd>

<title>When a man loves a woman</title>

<artist>Percy Sledge</artist>

<country>USA</country>

<company>Atlantic</company>

<price>8000</price>

<year>1987</year>

</cd>

<cd>

<title>Pavarotti Gala Concert</title>

<artist>Luciano Pavarotti</artist>

<country>UK</country>

<company>DECCA</company>

<price>13000</price>

<year>1991</year>

</cd>

 <cd>

<title>Unchain my heart</title>

<artist>Joe Cocker</artist>

<country>USA</country>

<company>EMI</company>

<price>10000</price>

<year>1987</year>

</cd>

</catalog>



아래의 XPath 식(expression)은 루트 엘러먼트인  catalog를 선정한다.

/catalog 

아래의 XPath 식은 catalog 엘러먼트 밑의 cd 엘러먼트를 선정한다.

/catalog/cd


아래의 XPath 식은 catalog 엘러먼트 밑의 cd 엘러먼트의 모든 price 엘러먼트를 선정한다.

/catalog/cd/price


Note: 경로가 /로 시작한다면 엘러먼트에 대한 절대 경로를 의미한다. 


3.2 XPath 의 구문


 XPath 는 문자열(string), 수(number), 불리언 표현을 취급하기 위한 표준함수의 라이브러리를 정의한다.  예를 들면 아래의 XPath 식은 price 엘러먼트의 값으로 10000원 이상의 값을 가지는 모든 cd 엘러먼트를 선정한다.  


/catalog/cd[price>10000]


XPath 는 XSLT 표준의 주요 부분으로 XSLT를 공부하려면 앞에서 설명한 바있다. 서두에도 이야기 하였듯이 XPath 는 1999년 10월 16일 XML 문서의 어드레싱 부분을 취급하는 언어로써 W3C 권고안으로 탄생하였으며 XSLT, XPointer 및 다른 파싱 소프트웨어에 의해 사용된다.


XPath 는 경로식(path expression)을 사용하여 XML 문서내의 노드를 찾는데 사용된다.

아래와 같은 XML 예제 문서를 보도록 하자.


<?xml version="1.0" encoding="EUC-KR"?>

<catalog>

<cd>

<title>San DoKaebi</title>

<artist>기둥SeulKiDoong</artist>

<country>Korea</country>

<company>Dongeui</company>

<price>8000</price>

<year>1992</year>

</cd>

<cd>

<title>Say Yes</title>

<artist>Chake&Aska</artist>

<country>Japan</country>

<company>Sony 레코드</company>

<price>12000</price>

<year>1992</year>

</cd>

<cd>

<title>Hound dog</title>

<artist>Elvis Presley</artist>

<country>USA</country>

<company>RCA</company>

<price>9000</price>

<year>1972</year>

</cd>

<cd>

<title>Still got the blues</title>

<artist>Gary Moore</artist>

<country>UK</country>

<company>Virgin records</company>

<price>10.20</price>

<year>1990</year>

</cd>

<cd>

<title>Romanza</title>

<artist>Andrea Bocelli</artist>

<country>EU</country>

<company>Polydor</company>

<price>15000</price>

<year>1996</year>

</cd>

<cd>

<title>When a man loves a woman</title>

<artist>Percy Sledge</artist>

<country>USA</country>

<company>Atlantic</company>

<price>8000</price>

<year>1987</year>

</cd>

<cd>

<title>Pavarotti Gala Concert</title>

<artist>Luciano Pavarotti</artist>

<country>UK</country>

<company>DECCA</company>

<price>13000</price>

<year>1991</year>

</cd>

 <cd>

<title>Unchain my heart</title>

<artist>Joe Cocker</artist>

<country>USA</country>

<company>EMI</company>

<price>10000</price>

<year>1987</year>

</cd>

</catalog>


1) 노드 찾기


 XML 문서는 우리가 컴퓨터의 폴더 구조에서 보는 것처럼 트리 구조로 표현된다.  XPath는 XML 문서 속에서 노드를 찾기 위해 패턴식(pattern expression)을 사용하며 XPath의 패턴은  /로 분리된 자식 엘러먼트의 이름들의 리스트로써 XML 문서에서의 경로를 표현하며  패턴은 경로에 매칭되는 엘러먼트를 선택한다.


아래의 XPath식은 catalog 엘러먼트의 모든 cd 엘러먼트의 price 엘러먼트를 선택한다.


/catalog/cd/price 


Note: /로 시작하는 경로는 엘러먼트에 대한 절대 경로를 나타낸다.


경로가  // 로 시작하면 경로에 관계없이 문서 속의 모든 엘러먼트에 대하여 주어진 기준(criteria)을 만족하는 엘러먼트를 선택한다.


아래의 XPath 경로는 문서 숙의 모든 cd 엘러먼트를 선택한다.


//cd 


알려지지 않은 엘러먼트 선택하기



와일드 카드(*) 는 알려지지 않은 엘러먼트를 선택하기 위해 사용된다.  아래의 XPath 식은 catalog 엘러먼트의 cd 엘러먼트의 모든 자식 노드를 선택하기 위해 사용된다. 


/catalog/cd/*


다음의 XPath 식은 catalog 엘러먼트의 손자 엘러먼트인 모든 price 엘러먼트를 선택한다.


/catalog/*/price 


아래의 XPath 식은 2 레벨의 조상 엘러먼트를 가진 모든 price 엘러먼트를 선택한다.


/*/*/price 


아래의 XPath 식은 경로에 관계없이 문서 속의 엘러먼트를 선택한다.


//*



2) 보다 자세하게 엘러먼트 선정하기


XPath 속의 대괄호[]를 이용하여 선택하고자 하는 엘러먼트를 보다 세밀하게 표현할 수 있다.


아래의 XPath 표현은 catalog 엘러먼트의 첫 번째 cd 자식을 선택한다.


/catalog/cd[1] 


아래의 XPath 표현은 catalog 엘러먼트의 마지막 cd 자식을 선택한다(그러나 first()라는 함수는 존재하지 않는다).


/catalog/cd[last()] 


아래의 XPath 표현은 price 엘러먼트를 가진 catalog 엘러먼트의 모든 cd 엘러먼트를 선택한다.


/catalog/cd[price] 


아래의 XPath 표현은 price 엘러먼트의 값으로 9000을 가진 catalog 엘러먼트의 모든 cd 엘러먼트를 선택한다.


/catalog/cd[price=9000] 


아래의 XPath 표현은 price 엘러먼트의 값으로 9000을 가진 catalog 엘러먼트의 cd 엘러먼트의 모든 price 엘러먼트를 선택한다.


/catalog/cd[price=90000]/price



3) 여러 path를 선택하기


 | 연산자를 사용하며 여러 경로를 선택할 수 있다. 다음의 XPath 식은 catalog 엘러먼트의 cd 엘러먼트의 모든 title과 artist 엘러먼트를 선택한다.


/catalog/cd/title | /catalog/cd/artist


다음의 XPath 식은 문서 속에 있는 모든 title과 artist 엘러먼트를 선택한다.


//title | //artist


다음의 XPath 식은 문서 속에 있는 모든 title, artist, price 엘러먼트를 선택한다.


//title | //artist | //price


다음의 XPath 식은 문서 속에 있는 모든 artist 엘러먼트와 catalog 엘러먼트의 cd 엘러먼트의 모든 title 엘러먼트를 선택한다.


/catalog/cd/title | //artist


3.3 속성 선정하기


XPath에서는 모든 속성이 @로 명시되며  아래의 예는 country라는 이름을 가진 속성을 선택한다.


//@country


아래의 XPath 식은 country라는 속성을 가진 모든 cd 엘러먼트를 선택한다.


//cd[@country]



아래의 XPath 식은 어떠한 속성이라도 속성이 존재하는 cd 엘러먼트를 선택한다.


//cd[@*]


아래의 XPath 식은 속성 country의 값으로 UK를 가지는 모든 cd 엘러먼트를 선택한다.


//cd[@country='UK']


3.4 XPath의  위치 경로



1) 위치 경로 식(Location Path Expression)


위치 경로는 절대 또는 상대 경로 둘 중 하나이다. 절대 경로는 /로 시작하며 상대 위치 경로는 그렇지 않다.  그러나 두 방식 다 /로 구분된 하나 또는 그 이상의 위치 단계로 구성되어 있다.


An absolute location path:

/step/step/...

A relative location path:

step/step/...

위치 단계는 왼쪽에서 오른쪽으로 한번에 한 단계씩 체크한다. 즉, 각 단계에서 현재의 노드셋(node-set)에 속해 있는 각 노드를 대상으로 하여 체크한다. 만약 위치 경로가 절대 경로이면 현재의 노드셋은 루트 노드로 구성된다.  만약 위치 경로가 상대 경로이면 현재의 노드셋은 식에 사용된 노드로 구성된다.

위치 단계는 다음과 같은 요소로 구성된다.

축 : 위치 단계에 의해 선정된 노드와 현재 노드와의 트리 관계를 나타냄


노드 테스트 : 위치 단계에 의해 선정된 노드의 확장명과 노드 타입을 나타냄


0개 이상의 서술부 : 위치 단계에 의해 선정된 노드의 집합을 보다 상술하는 식



위치 단계의 문법은 다음과 같다.


axisname::nodetest[predicate]


예:


child::price[price=9.90]






2) 축과 노드 테스트(Axes and Node Tests)


축은 현재 노드와 관련 있는 노드 셋을 정의하고 노드 테스트는 축 안에 있는 노드를 정의 하며 노드에 대한 테스트를 이름 또는 유형으로 할 수 있다.



축 이름

Description

ancestor

현재 노드의 모든 조상 노드를 포함

Note: 이 축은 현재 노드가 루트인 경우를 제외하고는 항상 루트를 포함하고 있다.

ancestor-or-self

현재 노드와  현재 노드의 모든 조상 노드를 포함

attribute

현재 노드의 모든 속성을 포함

child

현재 노드의 모든 자식 노드를 포함

descendant

현재 노드의 모든 후손 노드를 포함

Note: 이 축은 이름 공간이나 속성은 포함하지 않는다.

descendant-or-self

현재 노드 및 현재노드의 후손 노드를 포함

following

현재 노드의 태그를 종료한 뒤에 있는 문서 속에 있는 모든 것을 포함

following-sibling

현재 노드의 모든 형제 노드를 포함

Note: 현재의 노드가 속성 노드 또는 이름 공간 노드라면 이 축은 비어있음

namespace

현재 노드의 모든 이름 공간 노드를 포함

parent

현재 노드의 부모 노드를 포함

preceding

문서 속에서 현재 노드의 시작 태그 앞에 존재하는 모든 것을 포함

preceding-sibling

현재 노드 앞의 모든 형제 노드를 포함

Note: 현재 노드가 속성 노드 또는 이름공간 노드일 경우 이 축은 비어있음

self

현재 노드를 포함



Example

Result

child::cd

현재노드의 자식 노드인 모든 cd 엘러먼트를 선택한다.(만약 현재 노드가 자식이 없으면 빈 노드셋을 선택한다)

attribute::src

현재 노드의 src 속성을 선택한다.(만약 현재 노드가 src 속성을 가지고 있지 않다면 빈 노드셋을 선택한다)

child::*

현재 노드의 모든 자식 엘러먼트를 선택한다

attribute::*

현재 노드의 모든 속성을 선택한다

child::text()

현재 노드의 택스트 노드 자식을 선택한다

child::node()

현재 노드의 모든 자식을 선택한다

descendant::cd

현재 노드의 모든 cd 엘러먼트 자손을 선택한다.

ancestor::cd

현재 노드의 모든 cd 조상들을 선택한다.

ancestor-or-self::cd

현재 노드의 모든 cd 조상들을 선택한다. 만약 현재 노드가 cd 엘러먼트이면 현재 노드도 포함한다

child::*/child::price

현재 노드의 모든 price 손자 노드를 선택한다

/

문서의 루트를 선택한다

3) 서술 부(Predicates)

서술부는 [] 속에 놓여지며 노드셋을 필터링하여 새로운 노드 셋을 만들어낸다.

결과

child::price[price=9000]

현재 노드의 모든 price 자식 엘러먼트중 값이 9000인 price 엘러먼트를 선택

child::cd[position()=1]

현재 노드의 첫 cd 엘러먼트를 선택

child::cd[position()=last()]

현재 노드의 마지막 cd 엘러먼트를 선택

child::cd[position()=last()-1]

현재 노드의 cd 자식 노드 중 마지막에서 두 번째 cd 자식 엘러먼트를 선택

child::cd[position()<6]

현재 노드의 첫 다섯 cd 자식 노드를 선택

/descendant::cd[position()=7]

문서 속의 7번째 cd 엘러먼트를 선택

child::cd[attribute::type="classic"]

현재 노드의 cd 엘러먼트 중 type 속성으로 classic이라는 값을 가지는 엘러먼트 선택

4) 위치 경로의 단축된 문법

경로 위치를 표현하기 위해 압축된 문법을 사용하며 가장 중요한 압축된 표현은 child:: 로써 위치 단계에서 생략될 수 있다.


약칭

의미

예제

없음

child::

 cd 는 child::cd의 줄인 표현

@

attribute::

 cd[@type="classic"]은 child::cd[attribute::type="classic"]의 줄인 표현

.

self::node()

 .//cd 는 self::node()/descendant-or-self::node()/child::cd 의 줄인 표현

..

parent::node()

 ../cd 는 parent::node()/child::cd 의 줄인 표현

//

/descendant-or-self::node()/

 //cd 는 /descendant-or-self::node()/child::cd 의 줄인 표현


결과

cd

현재 노드의 모든 자식 cd 엘러먼트를 선택

*

현재 노드의 모든 자식 엘러먼트를 선택

text()

현재 노드의 모든 텍스트 노드 자식을 선택

@src

현재 노드의 모든 src 속성을 선택

@*

현재 노드의 모든 속성을 선택

cd[1]

현재 노드의 첫 번째 자식을 선택

cd[last()]

현재 노드의 마지막 자식을 선택

*/cd

현재 노드의 모든 손자 노드를 선택

/book/chapter[3]/para[1]

book의 chapter[3]의 첫 para를 선택

//cd

문서의 루트의 모든 cd 자손들을 선택하고 나서 해당 문서를 현재 노드로 하여 모든 cd 엘러먼트를 선택

.

현재 노드 선택

.//cd

현재 노드의 cd 엘러먼트 자손들을 선택

..

현재 노드의 부모를 선택

../@src

현재 노드의 부모의 src 속성을 선택

cd[@type="classic"]

현재 노드의 모든 cd 자식 노드중 type 속성으로 classic을 갖는 자식을 선택

cd[@type="classic"][5]

현재 노드의 cd 자식 노드중 type 속성으로 classic을 갖는 자식중 5번째 자식을 선택

cd[5][@type="classic"]

현재 노드의 5번째 cd 자식 노드가 ype 속성으로 classic을 갖는 다면 선택

 

cd[@type and @country]

현재 노드의 모든 cd 자식 중 속성으로 type과 country를 가지는 자식을 선택

3.5 XPath 식


XPath 는 수치, 등식, 관계 및 불리언 연산을 지원한다.


1) 수치 표현식(Numerical Expressions)


수치 표현식은 수치에 대하여 산술연산을 시행하기 위하여 사용된다.


연산자

설명

예제

결과 

+

더하기

6 + 4

10

-

빼기

6 - 4

2

*

곱하기

6 * 4

24

div

나누기

8 div 4

2

mod

Modulus (나누기의 나머지)

5 mod 2

1

Note: XPath 는 산술 연산을 시행하기 전에 각 피연산자를 수치로 바꾼 다음 계산한다.

2) 등호 연산(Equality Expressions)

등호 연산은 두 값의 동일 여부를 테스트하기 위해 사용한다.


연산자

설명

예제

결과

=

 같음

price=9.80

참 (만약 price is 9000 이면)

!=

 같지 않음

price!=9.80

거짓

3) 노드 셋에 대한 테스트

만약 test value 가 노드 셋에 대한 등호 연산을 시행하였다면 만약 해당 노드 셋에 test value를 만족하는 값이 하나라도 있다면 결과는 참이 된다.

만약 test value가 노드 셋에 대하여 부등호 연산을 시행하였다면 만약 해당 노드셋에 test value를 만족하지 않는 것이 하나라도 있다면 결과는 거짓이 된다.

결론은 노드 셋이 동시에 참이 될 수 도 있고 거짓이 될 수 도 있다는 것이다.


4) 관계식(Relational Expressions)


관계식은 두 값을 비교하기 위해 사용된다.


연산자

설명

예제

결과

<

작음

price<8000

거짓(만약 price가 9000이면)

<=

작거나 같음

price<=9000

>

price>9000

거짓

>=

크거나 같음

price>=9000

Note: XPath 는 연산을 시행하기 전에 각 피연산자를 수치로 바꾼 다음 계산한다.

5) 불리언식(Boolean Expressions)

불리언 식은 두 값을 비교하기 위하여 사용된다.

연산자

설명

예제

결과

or

or

price=9000 or price=8000

참 (만약 price is 8000이면)

and

and 

price<=9000 and price>=8000

거짓e

6) XPath 함수

XPath 는 데이터 변환을 위한 함수 라이브러리를 포함하고 있다.


XPath 함수 라이브러리


XPath 함수 라이브러리는 데이터를 변환, 번역하기 위한 중요 함수를 포함하고 있다.


노드 셋 함수(Node Set Functions)


이름

설명

count()

선택된 엘러먼트의 수를 반환

id()

Selects 엘러먼트들을 그들 고유의 ID로 선택

last()

식 평가 컨텍스트(expression evaluation context)로부터 컨텍스트의 크기에 해당하는 수를 반환

local-name()

문서 순서에서 첫 번째인 인수 노드셋(argument node-set)의 노드의 확장명의 local part를 반환

name()

엘러먼트의 이름을 반환

namespace-uri()

문서 순서에서 첫 번째인 인수 노드셋(argument node-set)의 노드의 확장명의 이름 공간 URI를 반환

position()

식 평가 컨텍스트(expression evaluation context)로부터 컨텍스트의 포지션에 해당하는 수를 반환

문자열 함수(String Functions)

이름

설명

예제 및 결과

concat()

Returns 인수의 연접을 반환

concat('The',' ','XML')

결과: 'The XML'

contains()

첫 번째 문자열이 두 번째 문자열을 포함하고 있으면 참이며 그 이외에는 거짓

contains('XML','X')

결과: true

normalize-space()

앞뒤의 공백을 제거

normalize-space(' The XML')

결과: 'The XML'

starts-with()

첫 번째 문자열이 두 번째 문자열로 시작하면 참이며 그 이외에는 거짓

starts-with('XML','X') 

결과: true

string()

객체를 문자열로 변환

string(3.14) 

결과: '3,14'

string-length()

문자열 속의 문자의 개수를 반환

string-length('Beatles') 

결과: 7

substring()

부분 문자열을 반환

substring('Beatles',1,4) 

결과: 'Beat'

substring-after()

부분 문자열 뒤의 부분 문자열을 반환

substring-after('12/10','/')

결과: '10'

substring-before()

부분 문자열 앞의 부분 문자열을 반환

substring-before('12/10','/') 

결과: '12'

translate()

문자를 문자열로 변환

translate('12:30',':','!') 

결과: '12!30'

수치 함수(Number Functions)

이름

설명

예제 및 결과

ceiling()

인수보다 크지 않은 작은 정수 반환

ceiling(3.14) 

결과: 4

floor()

인수보다 크기 않은 가장 큰 정수 반환

floor(3.14)

결과: 3

number()

인수를 수로 변환

number(price)

round()

인수에 가장 근접한 정수를 반환

round(3.14) 

결과: 3

sum()

인수 노드 셋의 각 노드에 대한 노드의 문자열 값을 수로 변환한 결과의 합을 반환

sum(/cd/price)

불리언 함수(Boolean Functions)

이름

설명

예제 및 결과

boolean()

인수를 불리언으로 변환

 

false()

거짓 반환

number(false()) 

결과: 0

lang()

 

 

not()

인수가 참이면 거짓 반환, 나머지의 경우는 거짓

not(false())

true()

참 반환

number(true())

결과 : 1

3.5 XPath 예제

지금 까지 배운 내용을 앞의 예제를 사용하여 설명한다.

collection.xml



<?xml version="1.0" encoding="EUC-KR"?>

<catalog>

<cd>

<title>San DoKaebi</title>

<artist>기둥SeulKiDoong</artist>

<country>Korea</country>

<company>Dongeui</company>

<price>8000</price>

<year>1992</year>

</cd>


<cd>

<title>Say Yes</title>

<artist>Chake&Aska</artist>

<country>Japan</country>

<company>Sony 레코드</company>

<price>12000</price>

<year>1992</year>

</cd>

<cd>

<title>Hound dog</title>

<artist>Elvis Presley</artist>

<country>USA</country>

<company>RCA</company>

<price>9000</price>

<year>1972</year>

</cd>

<cd>

<title>Still got the blues</title>

<artist>Gary Moore</artist>

<country>UK</country>

<company>Virgin records</company>

<price>10.20</price>

<year>1990</year>

</cd>

<cd>

<title>Romanza</title>

<artist>Andrea Bocelli</artist>

<country>EU</country>

<company>Polydor</company>

<price>15000</price>

<year>1996</year>

</cd>

<cd>

<title>When a man loves a woman</title>

<artist>Percy Sledge</artist>

<country>USA</country>

<company>Atlantic</company>

<price>8000</price>

<year>1987</year>

</cd>

<cd>

<title>Pavarotti Gala Concert</title>

<artist>Luciano Pavarotti</artist>

<country>UK</country>

<company>DECCA</company>

<price>13000</price>

<year>1991</year>

</cd>

 <cd>

<title>Unchain my heart</title>

<artist>Joe Cocker</artist>

<country>USA</country>

<company>EMI</company>

<price>10000</price>

<year>1987</year>

</cd>

</catalog>


노드 선정


지금부터는 XML 문서로부터 어떻게 노드들을 추출하는지를 인터넷 익스플로러에서 selectNode 함수를 사용하여 보여준다.  이 함수는 경로식을 인자로써 사용할 것이다.


xmlobject.selectNodes(XPath expression)


cd 노드 선택


아래의 예제는 catalog의 모든 cd를 선택하는 예제이다.


xmlDoc.selectNodes("/catalog/cd")


코드 :


<html>

<body>

<script type="text/vbscript">


set xmlDoc=CreateObject("Microsoft.XMLDOM")

xmlDoc.async="false"

xmlDoc.load("cdcatalog.xml")


path="/catalog/cd"

set nodes=xmlDoc.selectNodes(path)


for each x in nodes

  document.write("<xmp>")

  document.write(x.xml)

  document.write("</xmp>")

next


</script>

</body>

</html>



결과 :


<cd>

<title>San DoKaebi</title>

<artist>기둥SeulKiDoong</artist>

<country>Korea</country>

<company>Dongeui</company>

<price>8000</price>

<year>1992</year>

</cd>


<cd>

<title>Say Yes</title>

<artist>Chake&Aska</artist>

<country>Japan</country>

<company>Sony 레코드</company>

<price>12000</price>

<year>1992</year>

</cd>

<cd>

<title>Hound dog</title>

<artist>Elvis Presley</artist>

<country>USA</country>

<company>RCA</company>

<price>9000</price>

<year>1972</year>

</cd>

<cd>

<title>Still got the blues</title>

<artist>Gary Moore</artist>

<country>UK</country>

<company>Virgin records</company>

<price>12000</price>

<year>1990</year>

</cd>

<cd>

<title>Romanza</title>

<artist>Andrea Bocelli</artist>

<country>EU</country>

<company>Polydor</company>

<price>15000</price>

<year>1996</year>

</cd>

<cd>

<title>When a man loves a woman</title>

<artist>Percy Sledge</artist>

<country>USA</country>

<company>Atlantic</company>

<price>8000</price>

<year>1987</year>

</cd>

<cd>

<title>Pavarotti Gala Concert</title>

<artist>Luciano Pavarotti</artist>

<country>UK</country>

<company>DECCA</company>

<price>13000</price>

<year>1991</year>

</cd>

 <cd>

<title>Unchain my heart</title>

<artist>Joe Cocker</artist>

<country>USA</country>

<company>EMI</company>

<price>10000</price>

<year>1987</year>

</cd>




첫 번째 노드 선택하기


아래의 예제는 cd catalog의 첫 번째 cd 노드만을 선택한다.


mlDoc.selectNodes("/catalog/cd[0]")


코드 :


<html>

<body>

<script type="text/vbscript">


set xmlDoc=CreateObject("Microsoft.XMLDOM")

xmlDoc.async="false"

xmlDoc.load("cdcatalog.xml")


path="/catalog/cd[0]"

set nodes=xmlDoc.selectNodes(path)


for each x in nodes

  document.write("<xmp>")

  document.write(x.xml)

  document.write("</xmp>")

next


</script>

</body>

</html>



결과 :


<cd>

<title>San DoKaebi</title>

<artist>기둥SeulKiDoong</artist>

<country>Korea</country>

<company>Dongeui</company>

<price>8000</price>

<year>1992</year>

</cd>



Note: IE 5 에서는 [0]



price 노드 선택하기


아래의 코드는 cd catalog 로부터 모든 price 노드를 선택하는 예제이다.


xmlDoc.selectNodes("/catalog/cd/price")


코드 :


<html>

<body>

<script type="text/vbscript">


set xmlDoc=CreateObject("Microsoft.XMLDOM")

xmlDoc.async="false"

xmlDoc.load("cdcatalog.xml")


path="/catalog/cd/price"

set nodes=xmlDoc.selectNodes(path)


for each x in nodes

  document.write("<xmp>")

  document.write(x.xml)

  document.write("</xmp>")

next


</script>

</body>

</html>


결과 :


<price> 8000 </price>

<price> 12000 </price>

<price> 9000 </price>

<price> 12000 </price>

<price> 15000 </price>

<price> 8000 </price>

<price> 13000 </price>

<price> 10000 </price>




price 텍스트 노드 선택하기


어래의 코드는 price 노드로부터 오직 텍스트만을 선택한다.


xmlDoc.selectNodes("/catalog/cd/price/text()")


코드 :


<html>

<body>

<script type="text/vbscript">


set xmlDoc=CreateObject("Microsoft.XMLDOM")

xmlDoc.async="false"

xmlDoc.load("cdcatalog.xml")


path="/catalog/cd/price/text()"

set nodes=xmlDoc.selectNodes(path)


for each x in nodes

  document.write("<xmp>")

  document.write(x.xml)

  document.write("</xmp>")

next


</script>

</body>

</html>



결과 :


8000

12000

9000

12000

15000

8000

13000

10000



price가 1200 이상인 cd 노드 선택


아래의 예제는 price가 12000이상인 모든 cd 노드를 선택한다.


<html>

<body>

<script type="text/vbscript">


set xmlDoc=CreateObject("Microsoft.XMLDOM")

xmlDoc.async="false"

xmlDoc.load("cdcatalog.xml")


path="/catalog/cd[price>10.80]"

set nodes=xmlDoc.selectNodes(path)


for each x in nodes

  document.write("<xmp>")

  document.write(x.xml)

  document.write("</xmp>")

next


</script>

</body>

</html>


결과 :


<cd>

<title>Say Yes</title>

<artist>Chake&Aska</artist>

<country>Japan</country>

<company>Sony 레코드</company>

<price>12000</price>

<year>1992</year>

</cd>

<cd>

<title>Still got the blues</title>

<artist>Gary Moore</artist>

<country>UK</country>

<company>Virgin records</company>

<price>12000</price>

<year>1990</year>

</cd>

<cd>

<title>Romanza</title>

<artist>Andrea Bocelli</artist>

<country>EU</country>

<company>Polydor</company>

<price>15000</price>

<year>1996</year>

</cd>

<cd>

<title>Pavarotti Gala Concert</title>

<artist>Luciano Pavarotti</artist>

<country>UK</country>

<company>DECCA</company>

<price>13000</price>

<year>1991</year>

</cd>



price가 1200 이상인 price 노드 선택


아레의 예제는 price가 12000이상인 모든 price 노드를 선택한다.


xmlDoc.selectNodes("/catalog/cd[price>10.80]/price")


코드 :


<html>

<body>

<script type="text/vbscript">


set xmlDoc=CreateObject("Microsoft.XMLDOM")

xmlDoc.async="false"

xmlDoc.load("cdcatalog.xml")


path="/catalog/cd[price>10.80]/price"

set nodes=xmlDoc.selectNodes(path)


for each x in nodes

  document.write("<xmp>")

  document.write(x.xml)

  document.write("</xmp>")

next


</script>

</body>

</html>



결과 :


<price>12000</price>

<price>12000</price>

<price>15000</price>

<price>13000</price>

[출처] XPath 문법|작성자 개구리


출처 - http://blog.naver.com/PostView.nhn?blogId=cardin9&logNo=20032909370






1
2
3
4
5
6
7
8
9
10
11
12
<aaa>
    <bbb>
        <ccc>
            <ddd aaa="bbb">rock</ddd>
            <eee>111</eee>
        </ccc>
        <ccc>
            <ddd>stripe</ddd>
            <eee>222</eee>
        </ccc>
    </bbb>
</aaa>

  

1. ddd의 TEXT가 rock인 것 가져오기

expresion= /aaa/bbb/ccc/ddd[text() = 'rock']

  

2. ddd의 TEXT가 rock인 것 형제들 가져 오기

expresion= /aaa/bbb/ccc/ddd[text() = 'rock']/following-sibling::*

  

3. ddd의 attribute aaa가 bbb인 것 가져오기

expresion=/aaa/bbb/ccc/ddd[@aaa='bbb']

  

4. 2번째 ddd 가져오기

expresion=/aaa/bbb/ccc/ddd[2]

  

5. 마지막 ddd 가져 오기

expresion=/aaa/bbb/ccc/ddd[last()]


출처 - http://moonlighting.tistory.com/71






xpath 를 이용할수 있다는 걸 알기전에는 무식하게도 Document 클래스의 getElementById() 나 getElementsByTagName() 메소드를 이용해서 

상당히 무식하게 난해한 코드로 xml 을 파싱하곤 했었다 -_-



어느날 문득 xpath 에 대해서 살짝 알게되고 나서 부터는 전에 쓰던 방법에 비해서는 아주 간결하고 이해하기 쉬운 코드로 xml 에서 원하는 데이터를 땡겨다 쓰는게 훨씬 수월해 졌다.




※ xpath 문법에 대해서 왠만한걸 쉽게 파악하기 위해서는 요 사이트에 가면 된다.

http://www.zvon.org/xxl/XPathTutorial/General/examples.html

요기 가서 보면 알겠지만 쉽게 쉽게 설명되있다. 

xpath 만 어느정도 쓸 수 있으면 xml 에서 원하는 데이터를 땡겨오는건 매우 쉬워지니 살짝 한번 연구해 보는걸 추천한다.





xpath를 이용해서 xml 에서 원하는 데이터를 파싱하는 예제코드를 작성해 보았다. 

xpath 를 사용하기 위해서 별다로 다른 라이브러리를 classpath 에 추가 안해도 된다.




예제 코드에서 사용된 xml

1
2
3
4
5
6
7
8
9
10
<root>
    <row>
        <col1 id="c1">값1</col1>
        <col2 id="c2" val="val2">값2</col2>
    </row>
    <row>
        <col1 id="c3">값3</col1>
        <col2 id="c4">값4</col2>
    </row>
</root>



예제 코드는 다음과 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import java.io.StringReader;
 
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
 
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
 
 
public class XPathTest{
    public static void main(String[] args) throws Exception {
        String xml = "<root><row><col1 id='c1'>값1</col1><col2 id='c2' val='val2'>값2</col2></row>" +
                             "<row><col1 id='c3'>값3</col1><col2 id='c4'>값4</col2></row></root>";
         
        // XML Document 객체 생성
        InputSource is = new InputSource(new StringReader(xml));
        Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
 
        // 인터넷 상의 XML 문서는 요렇게 생성하면 편리함.
        //Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder()
        //                               .parse("http://www.example.com/test.xml");
         
         
         
        // xpath 생성
        XPath xpath = XPathFactory.newInstance().newXPath();
         
 
         
         
        // NodeList 가져오기 : row 아래에 있는 모든 col1 을 선택
        NodeList cols = (NodeList)xpath.evaluate("//row/col1", document, XPathConstants.NODESET);
        for( int idx=0; idx<cols.getLength(); idx++ ){
            System.out.println(cols.item(idx).getTextContent());
        }
        // 값1   값3  이 출력됨
         
         
         
         
         
        // id 가 c2 인 Node의 val attribute 값 가져오기
        Node col2 = (Node)xpath.evaluate("//*[@id='c2']", document, XPathConstants.NODE);
        System.out.println(col2.getAttributes().getNamedItem("val").getTextContent());
        // val2 출력
         
         
         
         
         
        // id 가 c3 인 Node 의 value 값 가져오기
        System.out.println(xpath.evaluate("//*[@id='c3']", document, XPathConstants.STRING));
        // 값3 출력
    }
}


전에 getElementById(), getElementsByTagName() 요걸 쓰던 코드에 비하면 코드도 쉽게 읽히고 심플하기도 서울역에 그지없다.

앞으로 xml 파싱할때는 xpath 를 주로 써야겠다.



※ evalueate() 메소드 맨 끝에 들어가는 파라메터로

XPathConstants.NODESET
XPathConstants.NODE
XPathConstants.BOOLEAN
XPathConstants.NUMBER
XPathConstants.STRING

요런걸 쓸 수 있다. 변수 이름을 보면 대충 어떨때 써야 할지 알 수 있을것이라 생각한다.


출처 - http://stove99.tistory.com/106





'Development > XML' 카테고리의 다른 글

XQuery  (0) 2013.02.20
XSL(Extensible Stylesheet Language)  (0) 2013.02.19
XML - XML 스키마(XSD) 및 xsi 접두어 의미  (0) 2012.10.02
XML - XML 예약문자  (0) 2012.09.16
xml namespace  (0) 2012.03.24
Posted by linuxism
,


Android

Gmail에 액세스하기 위해 Android 기기에서 'Email' 애플리케이션을 구성하려면 다음 단계를 따르세요.

  1. Gmail 환경설정에서 IMAP를 사용하도록 설정합니다.
  2. 휴대전화에서 < 홈 >을 누른 다음 Email 애플리케이션을 엽니다.
  3. '사용자 계정' 페이지에서 다음을 선택하여 설정을 시작합니다.
  4. 전체 Gmail 주소와 비밀번호를 입력하고 다음을 선택합니다.
  5. 다음 화면에서 계정에 닉네임을 지정하고 보내는 메일에 표시할 이름을 선택할 수 있습니다. 완료를 누릅니다.

설정이 완료되었습니다. < 메뉴 > > 계정 설정을 눌러 받은편지함에서 환경설정을 확인할 수 있습니다.

수신 설정
IMAP 서버: imap.gmail.com
포트: 993
보안 유형: SSL(항상)

발신 설정
SMTP 서버: smtp.gmail.com
포트: 465
보안 유형: SSL(항상)

이제 계정이 설정되었으므로 클라이언트에서의 동작이 Gmail과 동기화되는 방식을 알아보세요.


출처 - http://support.google.com/mail/answer/114408?hl=ko&cbrank=1&cbid=w045v42tue9&ctx=cb&src=cb






A List of SMTP and POP3 Servers (Mail Server)
The following list of SMTP and POP3 server should help you if you don't know what mail server you should use for your mail account.

This list is without any warranties and NOT sorted alphabetically.
Please send in corrections or contact us if your mailserver (mailprovider) is not listed below.

See also:  A List of SMTP and IMAP Mailservers (Mailserver List)

Default Ports:

  • SMTP AUTH: Port 25 or 587 (some ISPs are blocking port 25)
  • SMTP StartTLS Port 587
  • SMTP SSL Port 465
  • POP Port 110
  • POP SSL Port 995

SMTP Server (Outgoing Messages)



POP3 Server (Incoming Messages)


Googlemail/Gmail SMTP POP3 Server

smtp.gmail.com
SSL Port 465(사용가)
StartTLS Port 587

pop.gmail.com
SSL Port 995
Please make sure, that POP3 access is enabled in the account settings. Login to your account and enable POP3.
Outlook.com SMTP POP3 Server
smtp.live.com
StartTLS Port 587
pop3.live.com
SSL Port 995
Yahoo Mail SMTP POP3 Server
smtp.mail.yahoo.com
SSL Port 465
pop.mail.yahoo.com
SSL Port 995
Yahoo Mail Plus SMTP POP3 Server
plus.smtp.mail.yahoo.com
SSL Port 465
plus.pop.mail.yahoo.com
SSL Port 995
Yahoo UK SMTP POP3 Server
smtp.mail.yahoo.co.uk
SSL Port 465
pop.mail.yahoo.co.uk
SSL Port 995
Yahoo Deutschland SMTP POP3 Server
smtp.mail.yahoo.de
SSL Port 465
pop.mail.yahoo.de
SSL Port 995
Yahoo AU/NZ SMTP POP3 Server
smtp.mail.yahoo.com.au
SSL Port 465
pop.mail.yahoo.com.au
SSL Port 995
O2 SMTP POP3 Server
smtp.o2.ie
smtp.o2.co.uk
pop3.o2.ie
pop3.o2.co.uk
AT&T SMTP POP3 Server
smtp.att.yahoo.com
SSL Port 465
pop.att.yahoo.com
SSL Port 995

NTL @ntlworld.com SMTP POP3 Server

smtp.ntlworld.com
SSL Port 465
pop.ntlworld.com
SSL Port 995

BT Connect SMTP POP3 Server

pop3.btconnect.commail.btconnect.com

BT Openworld & BT Internet SMTP POP3 Server

mail.btopenworld.com
mail.btinternet.com
mail.btopenworld.com
mail.btinternet.com

Orange SMTP POP3 Server

smtp.orange.net
smtp.orange.co.uk
pop.orange.net
pop.orange.co.uk

Wanadoo UK SMTP POP3 Server

smtp.wanadoo.co.ukpop.wanadoo.co.uk
Hotmail SMTP POP3 Server
smtp.live.com
StartTLS Port 587
pop3.live.com
SSL Port 995
O2 Online Deutschland SMTP POP3 Server
mail.o2online.depop.o2online.de
T-Online Deutschland SMTP POP3 Server
smtpmail.t-online.de (AUTH)
securesmtp.t-online.de (SSL)
popmail.t-online.de (AUTH)
securepop.t-online.de (SSL)
1&1 (1and1) SMTP POP3 Server
smtp.1and1.com
StartTLS Port 25 or 587
pop.1and1.com
SSL Port 995
1&1 Deutschland SMTP POP3 Server
smtp.1und1.de
StartTLS Port 25 or 587
pop.1und1.de
SSL Port 995
Comcast SMTP POP3 Server
smtp.comcast.net
Port 587
mail.comcast.net
Verizon SMTP POP3 Server
outgoing.verizon.net
SSL Port 465
incoming.verizon.net
SSL Port 995
Verizon SMTP POP3 Server hosted on Yahoo Server
outgoing.yahoo.verizon.netincoming.yahoo.verizon.net


출처 - http://www.arclab.com/products/amlc/list-of-smtp-and-pop3-servers-mailserver-list.html




'Development > Common' 카테고리의 다른 글

GUID(Globally Unique Identifier)  (0) 2014.04.02
MD 확장자  (0) 2013.03.27
context  (0) 2012.11.21
accessor 와 mutator  (0) 2012.11.05
ISO 8601 - 날짜와 시간 표기 국제 표준 규격  (1) 2012.10.02
Posted by linuxism
,

EHCache

Computer Science/Cache 2013. 2. 11. 08:02


참고 - http://linuxism.tistory.com/1265





EHCache를 이용한 기본적인 캐시 구현 방법 및 분산 캐시 구현 방법을 살펴본다.

EHCache의 주요 특징 및 기본 사용법

게시판이나 블로그 등 웹 기반의 어플리케이션은 최근에 사용된 데이터가 또 다시 사용되는 경향을 갖고 있다. 80:20 법칙에 따라 20%의 데이터가 전체 조회 건수의 80%를 차지할 경우 캐시를 사용함으로써 성능을 대폭적으로 향상시킬 수 있을 것이다.

본 글에서는 캐시 엔진 중의 하나인 EHCache의 사용방법을 살펴보고, Gaia 시스템에서 EHCache를 어떻게 사용했는 지 살펴보도록 하겠다.

EHCache의 주요 특징

EHCache의 주요 특징은 다음과 같다.

  • 경량의 빠른 캐시 엔진
  • 확장(scable) - 메모리 & 디스크 저장 지원, 멀티 CPU의 동시 접근에 튜닝
  • 분산 지원 - 동기/비동기 복사, 피어(peer) 자동 발견
  • 높은 품질 - Hibernate, Confluence, Spring 등에서 사용되고 있으며, Gaia 컴포넌트에서도 EHCache를 사용하여 캐시를 구현하였다.
기본 사용법

EHCache를 사용하기 위해서는 다음과 같은 작업이 필요하다.

  1. EHCache 설치
  2. 캐시 설정 파일 작성
  3. CacheManager 생성
  4. CacheManager로부터 구한 Cache를 이용한 CRUD 작업 수행
  5. CacheManager의 종료
EHCache 설치

EHCache 배포판은 http://ehcache.sourceforge.net/ 사이트에 다운로드 받을 수 있다. 배포판의 압축을 푼 뒤, ehcache-1.2.x.jar 파일이 생성되는 데, 이 파일을 클래스패스에 추가해준다. 또한, EHCache는 자카르타의 commons-logging API를 사용하므로, commons-logging과 관련된 jar 파일을 클래스패스에 추가해주어야 한다.

ehcache.xml 파일

EHCache는 기본적으로 클래스패스에 존재하는 ehcache.xml 파일로부터 설정 파일을 로딩한다. 가장 간단한 ehcache.xml 파일은 다음과 같이 작성할 수 있다.

<ehcache>
    <diskStore path="java.io.tmpdir"/>

    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
            />
    
    <cache name="simpleBeanCache"
            maxElementsInMemory="10"
            eternal="false"
            overflowToDisk="false"
            timeToIdleSeconds="300"
            timeToLiveSeconds="600"
            memoryStoreEvictionPolicy="LRU" />

</ehcache>

위 코드에서 <defaultCache> 태그는 반드시 존재해야 하는 태그로서, 코드에서 캐시를 직접 생성할 때 사용되는 캐시의 기본 설정값을 저장한다. <cache> 태그는 하나의 캐시를 지정할 때 사용된다. name 속성은 캐시의 이름을 지정하며, 코드에서는 이 캐시의 이름을 사용하여 사용할 Cache 인스턴스를 구한다.

설정 파일에 대한 자세한 내용은 뒤에서 살펴보기로 하자.

CacheManager 생성

ehcache.xml 파일을 작성했다면 그 다음으로 할 작업은 net.sf.ehcache.CacheManager 객체를 생성하는 것이다. CacheManager 객체는 다음의 두 가지 방법 중 한가지 방식을 사용하여 생성할 수 있다.

  • CacheManager.create() : 싱글톤 인스턴스 사용
  • new CacheManager() : 새로운 CacheManager 인스턴스 생성
CacheManager.create() 메소드는 싱글톤 인스턴스를 생성하기 때문에 최초에 한번 호출될 때에만 CacheManager의 초기화 작업이 수행되며, 이후에는 동일한 CacheManager 인스턴스를 리턴하게 된다. 아래는 CacheManager.create() 메소드의 사용 예이다.

CacheManager cacheManager = CacheManager.create();

싱글톤 인스턴스가 아닌 직접 CacheManager 객체를 조작하려면 다음과 같이 new를 사용하여 CacheManager 인스턴스를 생성해주면 된다.

CacheManager cacheManager = new CacheManager();

두 방식 모두 클래스패스에 위치한 ehcache.xml 파일로부터 캐시 설정 정보를 로딩한다.

만약 클래스패스에 위치한 ehcache.xml 파일이 아닌 다른 설정 파일을 사용하고 싶다면 다음과 같이 URL, InputStream, 또는 String(경로) 객체를 사용하여 설정 파일의 위치를 지정할 수 있다.

URL configFile = this.getClass().getResource("/ehcache_config_replicate.xml")
CacheManager cacheManager = new CacheManager(configFile);

Cache에 CRUD 수행

CacheManager 인스턴스를 생성한 다음에는 CacheManager 인스턴스로부터 Cache 인스턴스를 구하고, Cache 인스턴스를 사용하여 객체에 대한 캐시 작업을 수행할 수 있게 된다. 

Cache 구하기
net.sf.ehcache.Cache 인스턴스는 CacheManager.getCache() 메소드를 사용하여 구할 수 있다.

CacheManager cacheManager = new CacheManager(configFileURL);
Cache cache = cacheManager.getCache("simpleBeanCache");

CacheManager.getCache() 메소드에 전달되는 파라미터는 ehcache.xml 설정 파일에서 <cache> 태그의 name 속성에 명시한 캐시의 이름을 의미한다. 지정한 이름의 Cache 인스턴스가 존재하지 않을 경우 CacheManager.getCache() 메소드는 null을 리턴한다.

Create/Update 작업 수행
Cache 인스턴스를 구한 다음에는 Cache.put() 메소드를 사용하여 캐시에 객체를 저장할 수 있다. 아래 코드는 Cache.put() 메소드의 사용예이다.

Cache cache = cacheManager.getCache("simpleBeanCache");

SimpleBean newBean = new SimpleBean(id, name);
Element newElement = new Element(newBean.getId(), newBean);
cache.put(newElement);

Cache.put() 메소드는 net.sf.ehcache.Element 객체를 전달받는다. Element 클래스는 캐시에 저장될 원소를 나타내며, 키와 값을 사용하여 원소를 표현한다. Element 객체를 생성할 때 첫번째 파라미터는 원소의 키를 의미하며, 두번째 파라미터는 원소의 값을 의미한다.

EHCache는 캐시에 저장될 각각의 객체들을 키를 사용하여 구분하기 때문에, Element 객체를 생성할 때 (의미상) 서로 다른 객체는 서로 다른 키를 사용해야 한다.

Map과 마찬가지로 EHCache가 제공하는 Cache는 삽입을 하거나 기존의 값을 수정할 때 모두 Cache.put() 메소드를 사용한다. 기존에 캐시에 저장된 객체를 수정하길 원한다면 다음과 같이 동일한 키를 사용하는 Element 객체를 Cache.put() 메소드에 전달해주면 된다.

Element newElement = new Element(id, someBean);
cache.put(newElement);
...
Element updatedElement = new Element(id, updatedBean);
cache.put(updatedElement);

Read 작업 수행
Cache에 보관된 객체를 사용하려면 Cache.get() 메소드를 사용하면 된다. Cache.get() 메소드는 키를 파라미터로 전달받으며, 키에 해당하는 Element 객체를 리턴하며 관련 Element과 존재하지 않을 경우 null을 리턴한다. 아래 코드는 Cache.get() 메소드의 사용예이다.

Element element = cache.get(key);
SimpleBean bean = (SimpleBean) element.getValue();

Element.getValue() 메소드는 캐시에 저장된 객체를 리턴한다. 만약 Serializable 하지 않은 객체를 값으로 저장했다면 다음과 같이 Element.getObejectValue() 메소드를 사용하여 값을 구해야 한다.

Element element = cache.get(key);
NonSerializableBean bean = (NonSerializableBean) element.getObjectValue();

Delete 작업 수행
Cache에 보관된 객체를 삭제하려면 Cache.remove() 메소드를 사용하면 된다. 아래 코드는 Cache.remove() 메소드의 사용예이다.

boolean deleted = cache.remove(key);

Cache.remove() 메소드는 키에 해당하는 객체가 존재하여 삭제한 경우 true를 리턴하고, 존재하지 않은 경우 false를 리턴한다.

CacheManager의 종료

사용이 종료된 CacheManager는 다음과 같이 shutdown() 메소드를 호출하여 CacheManager를 종료해야 한다.

cacheManager.shutdown();

Cache 값 객체 사용시 주의사항

캐시에 저장되는 객체는 레퍼런스가 저장된다. 따라서, 동일한 키에 대해 Cache.put()에 전달한 Element의 값과Cache.get()으로 구한 Element의 값은 동일한 객체를 참조하게 된다.

SimpleBean bean = ...;
Element element = new Element(key, bean);
cache.put(element);

Element elementFromCache = cache.get(key);
SimpleBean beanFromCache = (SimpleBean)elementFromCache.getValue();

(bean == beanFromCache); // true
(element == elementFromCache); // false

위 코드에서 Cache.put()에 전달된 element 객체와 Cache.get()으로 구한 elementFromCache 객체는 서로 다른 객체이다. 하지만, 두 Element 객체가 갖고 있는 값은 동일한 객체를 참조하고 있다. 따라서, 캐시에 값으로 저장된 객체를 변경하게 되면 캐시에 저장된 내용도 변경되므로, 캐시 사용시 이 점에 유의해야 한다.

캐시 설정

캐시 설정 파일에 <cache> 태그를 이용하여 캐시를 설정했었다. 캐시 설정과 관련하여 <cache> 태그는 다양한 속성을 제공하고 있는데, 이들 속성에는 다음과 같은 것들이 존재한다.

name캐시의 이름필수
maxElementsInMemory메모리에 저장될 수 있는 객체의 최대 개수필수
eternal이 값이 true이면 timeout 관련 설정은 무시되고, Element가 캐시에서 삭제되지 않는다.필수
overflowToDisk메모리에 저장된 객체 개수가 maxElementsInMemory에서 지정한 값에 다다를 경우 디스크에 오버플로우 되는 객체는 저장할 지의 여부를 지정한다.필수
timeToIdleSecondsElement가 지정한 시간 동안 사용(조회)되지 않으면 캐시에서 제거된다. 이 값이 0인 경우 조회 관련 만료 시간을 지정하지 않는다. 기본값은 0이다.선택
timeToLiveSecondsElement가 존재하는 시간. 이 시간이 지나면 캐시에서 제거된다. 이 시간이 0이면 만료 시간을 지정하지 않는다. 기본값은 0이다.선택
diskPersistentVM이 재 가동할 때 디스크 저장소에 캐싱된 객체를 저장할지의 여부를 지정한다. 기본값은 false이다.선택
diskExpiryThreadIntervalSecondsDisk Expiry 쓰레드의 수행 시간 간격을 초 단위로 지정한다. 기본값은 120 이다.선택
memoryStoreEvictionPolicy객체의 개수가 maxElementsInMemory에 도달했을 때,모메리에서 객체를 어떻게 제거할 지에 대한 정책을 지정한다. 기본값은 LRU이다. FIFO와 LFU도 지정할 수 있다.선택

아래 코드는 몇 가지 설정 예이다.

<!--
sampleCache1 캐시. 최대 10000개의 객체를 저장할 수 있으며, 
5분 이상 사용되지 않거나 또는 10분 이상 캐시에 저장되어 있을 경우 
캐시에서 제거된다. 저장되는 객체가 10000개를 넘길 경우, 
디스크 캐시에 저장한다.
-->
<cache name="sampleCache1"
       maxElementsInMemory="10000"
       maxElementsOnDisk="1000"
       eternal="false"
       overflowToDisk="true"
       timeToIdleSeconds="300"
       timeToLiveSeconds="600"
       memoryStoreEvictionPolicy="LFU"
       />

<!--
sampleCache2 캐시. 최대 1000개의 객체를 저장한다. 
오버플로우 된 객체를 디스크에 저장하지 않기 때문에 
캐시에 최대 개수는 1000개이다. eternal이 true 이므로, 
timeToLiveSeconds와 timeToIdleSeconds 값은 무시된다.
-->
<cache name="sampleCache2"
       maxElementsInMemory="1000"
       eternal="true"
       overflowToDisk="false"
       memoryStoreEvictionPolicy="FIFO"
       />

<!--
sampleCache3 캐시. 오버플로우 되는 객체를 디스크에 저장한다.
디스크에 저장된 객체는 VM이 재가동할 때 다시 캐시로 로딩된다.
디스크 유효성 검사 쓰레드는 10분 간격으로 수행된다.
-->
<cache name="sampleCache3"
       maxElementsInMemory="500"
       eternal="false"
       overflowToDisk="true"
       timeToIdleSeconds="300"
       timeToLiveSeconds="600"
       diskPersistent="true"
       diskExpiryThreadIntervalSeconds="600"
       memoryStoreEvictionPolicy="LFU"
       />

분산 캐시

EHCache는 분산 캐시를 지원한다. EHCache는 피어(peer) 자동 발견 및 RMI를 이용한 클러스터간 데이터 전송의 신뢰성 등 분산 캐시를 위한 완전한 기능을 제공하고 있다. 또한, 다양한 옵션을 통해 분산 상황에 맞게 설정할 수 있도록 하고 있다.

참고로, EHCache는 RMI를 이용하여 분산 캐시를 구현하고 있기 때문에, Serializable 한 객체만 분산 캐시에서 사용 가능하다. 키 역시 Serializable 해야 한다.

분산 캐시 구현 방식

EHCache는 한 노드의 캐시에 변화가 생기면 나머지 노드에 그 변경 내용을 전달하는 방식을 사용한다. 즉, 클러스터에 있는 캐시 인스턴스가 n개인 경우, 한번의 변경에 대해 n-1개의 변경 통지가 발생한다.

각 노드의 캐시간 데이터 전송은 RMI를 통해서 이루어진다. EHCache가 데이터 전송 기술로서 RMI를 사용하는 이유는 다음과 같다.

  • 자바에서 기본적으로 제공하는 원격 메커니즘
  • 안정화된 기술
  • TCP 소켓 옵션을 튜닝할 수 있음
  • Serializable 한 객체를 지원하기 때문에, 데이터 전송을 위해 XML과 같은 별도의 포맷으로 변경할 필요가 없음
노드 발견

EHCache는 클러스터에 새로운 노드가 추가돌 경우 해당 노드를 자동적으로 발견하는 방식과, 지정된 노드 목록에 대해서만 클러스터의 노드로 사용하는 방식을 지원하고 있다.

멀티캐스트 방식

멀티캐스트 모드를 사용한 경우, 지정한 멀티캐스트 IP(224.0.0.1~239.255.255.255)와 포트에 참여하는 노드를 자동으로 발견하게 된다. 지정한 IP와 포트에 참여한 노드는 자기 자신을 다른 노드에 통지한다. 이 방식을 사용하면 클러스터에 동적으로 노드를 추가하거나 제거할 수 있다.

노드 목록 지정 방식

클러스터에 포함되는 노드 목록을 지정한다. 동적으로 새로운 노드를 추가하거나 기존 노드를 제거할 수 없다.

분산 캐시 설정

분산 캐시를 사용하기 위해서는 다음과 같은 세 개의 정보를 지정해주어야 한다.

  • CacheManagerPeerProvider - 피어 발견 관련 설정
  • CacheManagerPeerListener - 메시지 수신 관련 설정
  • 캐시별 CacheReplicator - 메시지 생성 규칙 설정
CacheManagerPeerProvider 설정

CacheManagerPeerProvider는 새롭게 추가된 노드를 발견하는 방식을 지정한다.

노드를 자동으로 발견하는 멀티캐스트 방식을 사용하려면 다음과 같이 설정한다.

<cacheManagerPeerProviderFactory
    class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
    properties="peerDiscovery=automatic, 
                    multicastGroupAddress=230.0.0.100, multicastGroupPort=1234" />

위 코드에서 properties 속성의 값에 사용된 프로퍼티는 다음과 같다.

peerDiscoveryautomatic으로 지정하면 멀티캐스트 방식을 사용한다.
multicaseGroupAddress멀티캐스트 IP
multicaseGroupPort포트 번호

하나의 클러스터에 포함될 노드들은 동일한 멀티캐스트 IP와 포트 번호를 사용해야 한다.

클러스터에 참여할 노드 목록을 지정하는 IP 방식을 사용하려면 다음과 같이 설정한다.

<cacheManagerPeerProviderFactory
    class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
    properties="peerDiscovery=manual, 
                    rmiUrls=//server2:12345/cache1|//server2:12345/cache2" />

위 코드에서 properties 속성의 값에 사용된 프로퍼티는 다음과 같다.

peerDiscoverymanual로 지정한 IP 지정 방식이다.
rmiUrls분산 노드에 참여할 서버 및 캐시 목록을 지정한다. 현재 노드의 정보는 포함시켜서는 안 된다.

이 경우, rmiUrls에 명시된 포트 번호는 뒤에 살펴볼 CacheManagerPeerListener가 사용할 포트 번호를 지정해주어야 한다.

CacheManagerPeerListener 설정

노드를 발견하는 방식을 지정했다면, 다음으로 할 작업은 클러스터에 있는 다른 노드에서 발생한 변경 정보를 수신할 때 사용할 포트 번호를 지정하는 것이다. 다음과 같은 코드를 이용하여 수신과 관련된 포트 번호를 설정할 수 있다.

<cacheManagerPeerListenerFactory
    class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
    properties="port=12345, socketTimeoutMillis=120000" />

위 코드에서 properties 속성의 값에 사용된 프로퍼티는 다음과 같다.

port메시지를 수신할 때 사용되는 포트
socketTimeoutMillis이 노드에 메시지를 보냈을 때 메시지 전송을 기다리는 시간. 기본값은 2000ms.

캐시별 CacheReplicator 설정

분산 환경에 적용되어야 하는 캐시는 캐시의 내용이 변경되었을 때 다른 노드에 있는 캐시에 변경 내역을 알려주어야 한다. <cacheEventListenerFactory> 태그를 사용하면, 언제 어떻게 캐시의 변경 내역을 통지할지의 여부를 지정할 수 있다. 아래 코드는 설정의 예이다.

<cache name="simpleBean"
      maxElementsInMemory="100"
      eternal="false"
      overflowToDisk="false"
      timeToIdleSeconds="300"
      timeToLiveSeconds="600"
      memoryStoreEvictionPolicy="LRU">
       <cacheEventListenerFactory 
           class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" 
           properties="replicateUpdatesViaCopy=true,replicateUpdates=true" />
</cache>

위 코드와 같이 <cacheEventListenerFactory>의 구현 클래스로 RMICacheReplicatorFactory를 지정하면 캐시에 변경이 생길 때 마다 해당 변경 내역을 클러스터에 참여하고 있는 노드의 캐시에 통지하게 된다. properties 속성에 프로퍼티를 지정하면, 캐시 요소의 추가, 변경, 삭제 등에 대해 통지 방식을 적용할 수 있다. 설정할 수 있는 프로퍼티는 다음과 같다.

replicatePuts캐시에 새로운 요소가 추가됐을 때 다른 노드에 복사할지의 여부
replicateUpdates캐시 요소의 값이 변경되었을 때 다른 노드에 값을 복사할지의 여부
replicateRemovals캐시 요소가 삭제되었을 때 다른 노드에 반영할지의 여부
replicateAsynchronously비동기로 값을 복사할지의 여부
replicateUpdatesViaCopy새로운 요소를 다른 노드에 복사할 지 아니면 삭제 메시지를 보낼지의 여부
asynchronousReplicationIntervalMillis비동기 방식을 사용할 때 변경 내역을 다른 노드에 통지하는 주기. 기본값은 1000.

위 속성의 기본값은 모두 true이다. 따라서, 기본 설정값을 사용하려면 다음과 같이 properties 속성을 사용하지 않아도 된다.

<cache name="simpleBean" ...
      memoryStoreEvictionPolicy="LRU">
       <cacheEventListenerFactory 
           class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
</cache>

어플리케이션 구동시 캐시 데이터 로딩하기

CacheManager가 초기화 될 때, 클러스터에 있는 다른 캐시로부터 데이터를 로딩할 수 있다. 이는 초기 구동이 완료된 후 곧 바로 서비스를 제공할 수 있음을 의미한다. 초기 구동시 다른 노드로부터 캐시 데이터를 로딩하려면 다음과 같이 <bootstrapCacheLoaderFactory> 태그의 구현 클래스를 RMIBootstrapCacheLoaderFactory로 지정해주면 된다.

<cache name="simpleBean" ...
      memoryStoreEvictionPolicy="LRU">
       <bootstrapCacheLoaderFactory
           class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
           properties="bootstrapAsynchronously=true,
                       maximumChunkSizeBytes=5000000" />

       <cacheEventListenerFactory 
           class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
</cache>

RMIBootstrapCacheLoaderFactory에 전달 가능한 프로퍼티 목록은 다음과 같다.

bootstrapAsynchronously비동기적으로 수행할지의 여부를 지정
maximumChunkSizeBytes클러스터의 다른 노드로부터 로딩 가능한 데이터의 최대 크기

RMIBoostrapCacheLoaderFactory를 설정하면 캐시를 초기화 할 때, 원격지 노드의 캐시에 저장된 데이터를 로딩하여 로컬 캐시에 저장한다.

분산 캐시 고려사항

분산 캐시를 사용할 때에는 다음과 같은 내용을 고려해야 한다.

  • 노드 증가에 따라 네트워크 트래픽 증가:
    많은 양의 네트워크 트래픽이 발생할 수 있다. 특히 동기 모드인 경우 성능에 영향을 받을 수 있다. 비동기 모드인 경우 버퍼에 변경 내역을 저장하였다가 일정한 주기로 버퍼에 쌓인 내역을 다른 노드에 통지하기 때문에 이 문제를 다소 완하시킬 수 있다.
  • 데이터 불일치 발생 가능성:
    두 노드에서 동시에 동일한 캐시의 동일한 데이터에 대한 변경을 수행할 경우, 두 노드 사이에 데이터 불일치가 발생할 수 있다. 캐시 데이터의 불일치가 매우 심각한 문제가 될 경우, 동기 모드(replicateAsynchronously=false)와 복사 메시지 대신 삭제 메시지를 전송(replicateUpdatesViaCopy=false)함으로써 이 문제를 해결할 수 있다.
관련링크:


출처 - http://javacan.tistory.com/123






Ehcache는 가장 표준적인 캐시의 모습을 한 오픈소스 캐시 라이브러리입니다. 얼마전 JCO에 갔을때 보니 이번엔 정말 캐시가 화두인것 같더군요. 하지만 당시에 발표된 대부분의 캐시 시스템은 Memcached, Redis같은 클러스터 기반의 외부형 초대규모 캐시들이었습니다. 이번에 간단하게 쓸 수 있는 캐시 라이브러리가 없을까 검색하다 보니 발견한 ehcache-spring-annotation 라이브러리는 캐시사용을 정말 쉽고 간단하게 만들어 줍니다.

자주 바뀌지 않는 결과물인, 가령 공지사항이라던가 페이지의 첫화면(index)과 같은 경우에 적극적으로 활용할 수 있을것 같습니다. 이번에 쓰는 글은 메이븐 기반의 프로젝트 구성을 할 예정입니다. 지식이 부족하시다면 [관련글]을 좀 더 보시고 오시면 도움이 될것입니다. 스프링 프로젝트의 구성에는 충분히 이해도가 높은 분들이 보시는 글이라 생각하고 그런 부분은 종종 건너 뛰도록 하겠습니다.

Maven 프로젝트 구성

임시로 사용할 프로젝트이니 다음과 같은 정도만 등록해주시면 될것 같습니다. XML을 올릴까 싶었지만 글중에 스크린샷 하나쯤 등장하는게 아름다울것 같아 다음의 스크린샷으로 대신합니다.
사용자 삽입 이미지

스프링 프로젝트 컨텍스트 설정에 ehcache 설정 추가

스프링의 컨텍스트 설정 XML에 다음의 코드를 추가해 줍니다. 설정파일이 여러개로 분산되어있다면 어디에 들어가던지 순서는 상관없습니다.
<ehcache:annotation-driven />
 
<ehcache:config cache-manager="cacheManager">
 
<ehcache:evict-expired-elements interval="300" />
</ehcache:config>

<bean id="cacheManager"
 
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
 
<property name="configLocation" value="/WEB-INF/cache/ehcache.xml" />
</bean>

여기서 중요한점은 <beans> 네임스페이스 선언에 다음이 추가되어야 합니다.
xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
xsi
:schemaLocation="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd"

보기가 어렵지만 달리 방법이 없네요. 결과적으로 다음과 같은 모습이 됩니다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
        xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd">
       
<ehcache:annotation-driven />

<ehcache:config cache-manager="cacheManager">
 
<ehcache:evict-expired-elements interval="300" />
</ehcache:config>

<bean id="cacheManager"
 
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
 
<property name="configLocation" value="/WEB-INF/cache/ehcache.xml" />
</bean>

</beans>

Ehcache 설정 파일 생성

이번엔 Ehcache의 설정 파일을 추가해주어야 합니다. 위에서 /WEB-INF/cache/ehcache.xml에 선언해 두었으므로 해당 위치에 추가해 주어야 합니다.
<?xml version="1.0" encoding="UTF-8"?>
<ehcache
 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
 
maxBytesLocalHeap="32M" maxBytesLocalOffHeap="128M"
 
maxBytesLocalDisk="0M" updateCheck="false">
       
 
<cache
   
name="CacheExample"
        maxElementsInMemory="100"
        eternal="false"
        overflowToDisk="false"
        timeToLiveSeconds="30" />
   
</ehcache>

위의 설정을 대충 보자면 CacheExample이라는 이름의 캐시를 생성을 합니다. 한번에 최대 100개의 엘리먼트를 보관(maxElementsInMemory)할 수 있으며 영원히 저장하지 않고(eternal) 특정 상황에서 삭제 되어도 상관없다는 설정이 되어있습니다. 디스크까지 저장하면 캐시의 의미가 퇴색되므로 디스크는 절대로 사용하지 않을것이고(overflowToDisk) 한번 꺼내온 데이터는 30초동안만 유지하겠습니다(timeToLiveSeconds). 30초가 지나면 데이터를 파기합니다.

<ehcache> 선언부에 있는 설정들은 전체 캐시를 총괄하는 글로벌 설정입니다.

DAO 클래스에 캐시 추가하기

다음과 같이 크게 기억해둘 부분은 두가지 입니다. 설정된 캐시 정보대로 값을 캐시하며 실제 내부 로직이 실행될지 캐시가 반환 될지를 결정할 @Cacheable 어노테이션과 캐시 설정과 상관없이 당장 캐시를 삭제하는 @TriggersRemove 어노테이션을 잘 봐두시면 됩니다.
@Repository
public class CacheDao
{
 
@TriggersRemove(cacheName="CacheExample", removeAll=true, when=When.AFTER_METHOD_INVOCATION)
 
public void insertDummy()
 
{
        // 캐시 삭제 예시를 위해 존재하는 메소드
 
}

 
@Cacheable(cacheName="CacheExample")
 
public String getDummy()
 
{
   
// 캐시가 존재할 경우 이 로직은 실행되지 않고 캐시가 바로 반환됩니다.
   
return new Date().toString();
 
}
}

테스트용 컨트롤러 제작하기

지금 보여드릴 코드는 순전히 테스트를 위한 코드입니다. 데이터를 가져오는 부분과 데이터를 날리는 부분이 있습니다.
@Controller
@RequestMapping("/example")
public class CacheController
{
 
@Autowired private CacheService cacheService;
 
 
@RequestMapping("/main")
 
public String showIndex(Model model)
 
{
    model
.addAttribute("now", cacheService.getDummy());
   
return "index";
 
}
 
 
@RequestMapping("/flush")
 
public String flushCache()
 
{
    cacheService
.insertDummy();
   
return "redirect:/example/main";
 
}
}


showIndex가 실행이 되면 cacheService를 통해 cacheDao를 통해 값을 가져오게 됩니다. 아까 설정했던 캐시 규칙에 의거해 한번 캐시된 데이터는 100개의 데이터를 넘지 않는 이상 30초간 캐시 됩니다. 뷰에서는 꺼내온 데이터를 그대로 찍도록 만들어져 있습니다.

캐싱 테스트 해보기


사용자 삽입 이미지
실행을 해보니깐 현재의 시간이 잘 출력이 됩니다. 하지만 다시한번 재 요청을 해보시면 시간이 변하지 않는것을 확인하실 수 있습니다. 계속 재 요청을 해도 같은 화면이 출력이 되며 30초 뒤에 캐시가 사라졌을법한 뒤에 다시 요청을 해 보시면 다시 DAO의 내부 로직이 실행되어 현재 시간이 출력됩니다.

여기서 flushCache를 실행하게 되면 곧바로 캐시가 삭제되어(실제로는 새로운 데이터가 입력되어 전체 데이터에 변동이 일어나 더이상 기존의 캐시가 유효하지 않게 되었으므로 삭제하는것이겠죠) 더이상 캐시가 유효하지 않게 되고 이후 원래 화면으로 리다이렉트 되면 다시 캐시없는 상태에서 데이터 가져오기가 실행되게 됩니다. 예시로 만들었던 소스를 올려 놓겠습니다.



참고:
http://code.google.com/p/ehcache-spring-annotations/w/list
http://blog.goyello.com/2010/07/29/quick-start-with-ehcache-annotations-for-spring/ 


출처 - http://theeye.pe.kr/entry/simple-way-of-caching-my-data-access-object-with-spring-annotation






spring cache의 적용(ehcache)


처리 속도 개선을 위해 cache를 적용했다.

시스템간 연동으로 접속부하, 네트웍부하가 동시에 생겨 속도저하가 심각한 화면이 생김!!

문제는 조회조건부 - 회계년도, 부서, 코드관련..... 
가져오는 데이터는 거의 동일한데도...
화면이 바뀌거나, 조회콤보 선택처리에 DB까지 데이터 엑세스가 반복적으로 발생.

이 부분에 cache를 적용해볼 생각으로 자료를 찾았더니 가장 많이 선택된 솔루션이 ehcache.....
ehcache를 심도있게 학습하고 적용할 상황은 아니라서 
spring에 annotation기반으로 빠르게 적용할 수 있는 방법을 찾음 ehcache-spring-annotations

현재 개발중인 시스템에 적용된 spring버전은 3.0.5.RELEASE이다.
maven을 사용하고 있다면 다음과 같은 dependency추가가 필요하다.

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context-support</artifactId>
   <version>3.0.5.RELEASE</version>
</dependency>

<dependency>
   <groupId>com.googlecode.ehcache-spring-annotations</groupId>
   <artifactId>ehcache-spring-annotations</artifactId>
   <version>1.1.3</version>
</dependency> 

위 2개의 dependency를 추가하면 그와 연결된 관련 dependency까지 setting이 완료된다. 
maven의 혜택...ㅋ~~~~ 

maven에 의해 ehcache관련 필수 라이브러리가 classpath상에 위치하게 되었으므로
설정과 코드수정만 남았다.

먼저 beans.xml 또는 applicationContext.xml 등 spring configuration파일의 
네임스페이스 부분에 추가설정이 필요

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring
                  http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd">
 
짙게 표시된 부분이  추가한 내용이다.

그리고 동일 설정파일에 아래 코드를 추가한다.

  <!-- declare ehCache -->
  <ehcache:annotation-driven />
  
  <ehcache:config cache-manager="cacheManager">
    <ehcache:evict-expired-elements interval="60" />
  </ehcache:config>
    
  <!-- ehCache bean -->
  <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" >
    <property name="configLocation"  value="/WEB-INF/ehcache.xml"/>
  </bean> 
 
이제 설정 작업은 끝났다.
WEB-INF/ root 디렉토리에 다음과 같은 내용의 ehcache.xml파일을 생성하자.

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false">   
    
    <defaultCache 
     eternal="false" 
     maxElementsInMemory="1000"
        overflowToDisk="false" 
        diskPersistent="false" 
        timeToIdleSeconds="0"
        timeToLiveSeconds="600" 
        memoryStoreEvictionPolicy="LRU"/>

    <cache 
     name="budgetCache" 
     eternal="false"
        maxElementsInMemory="100" 
        overflowToDisk="false" 
        diskPersistent="false"
        timeToIdleSeconds="0" 
        timeToLiveSeconds="300"
        memoryStoreEvictionPolicy="LRU" />
        
    <cache 
     name="accountCache" 
     eternal="false"
        maxElementsInMemory="100" 
        overflowToDisk="false" 
        diskPersistent="false"
        timeToIdleSeconds="0" 
        timeToLiveSeconds="300"
        memoryStoreEvictionPolicy="LRU" />
        
</ehcache>

배포파일의 element, 설정값 등은
환경에 맞게 수정해서 사용하면 될 것이다.

지금까지 한 작업을 정리해보면...
1. dependency추가 완료
2. spring configuration 파일(beans.xml 또는 applicationContext.xml 등 설정 파일) 설정 추가 완료
3. ehcache configuration 파일 작성 및 배포준비 완료(WEB-INF)

이제 실제 Java code에 적용하는 일만 남았다...
다음 코드는 @Cacheable annotation을 적용한 소스의 일부이다.

package pe.tuenas.prototype.soapservice.budget.impl;

import .... 생략

@WebService(
		endpointInterface="pe.tuenas.prototype.soapservice.budget.BudgetService", 
		serviceName="budgetService")
public class BudgetServiceImpl implements BudgetService {

    @Cacheable(cacheName = "budgetCache")
	@Override
	public List getBudgetTypeList(String workDate) {

		return getBudgetTypeDao().findBudgetTypeByFYear(
				getFinancialYearDao().findFinancialYearByDate(workDate));
	}
	
	@Cacheable(cacheName = "budgetCache")
	@Override
	public List getBudgetTypeListByBusinessYear(String businessYear) {
		return getBudgetTypeDao().findBudgetTypeByFYear(
				getFinancialYearDao().findFinancialYearByBusinessYear(businessYear));
	}
	
	@Cacheable(cacheName = "budgetCache")
	@Override
	public List getBusinessCodeList(String workDate) {

		return getBusinessCodeDao().findBusinessCodeByDate(workDate);
	}
}



@Cacheable annotation선언만으로 캐시기능은 훌륭하게 작동된다.
실제로 한게 너무 없어 황당할 정도...

서비스 영역의 캐시가 완료되면 client영역에서 최초 조회시 원래 속도로 나오고
반복적인 조회에서는 엄청난(?) 속도향상이 이뤄졌다.

cache적용이 유용한  부분은 
코드성 데이터 조회 부분, 
기본 데이터이지만 반복적으로 호출되는 부분  
출력물의 코드, 부서 매핑이 필요한 부분 등일 것이다..

웹상에 공개된 문서나 자료만을 참고해서 급하게 적용하느라 
심도있는 이해나 준비가 부족했다.
추후 보완이 필요한 부분이다.


출처 - http://ironheel.tistory.com/44











'Computer Science > Cache' 카테고리의 다른 글

Hazelcast 소개  (0) 2012.11.06
Memcached 설치 및 사용 방법  (0) 2012.11.06
Memcached의 확장성 개선  (0) 2012.11.06
memcached를 적용하여 사이트 성능 향상  (0) 2012.11.06
Memcached 구현 소개  (0) 2012.11.06
Posted by linuxism
,