XPath 튜토리얼

이 튜토리얼에서는 calibre에서 HTML 문서의 임의 부분을 선택하는 데 사용할 수 있는 쿼리 언어인 `XPath <https://en.wikipedia.org/wiki/XPath>`_에 대해 쉽게 소개합니다. XPath는 널리 사용되는 표준이며, 검색하면 많은 정보를 얻을 수 있습니다. 그러나 이 튜토리얼은 비정형 HTML 문서에서 장 머리글을 찾는 것과 같은 전자책 관련 작업에 XPath를 사용하는 데 초점을 맞춥니다.

태그 이름으로 선택

가장 간단한 선택 형태는 이름으로 태그를 선택하는 것입니다. 예를 들어, 문서의 모든 <h2> 태그를 선택하고 싶다고 가정합니다. 이에 대한 XPath 쿼리는 간단합니다:

//h:h2        (Selects all <h2> tags)

접두사 //`는 *문서의 모든 수준에서 검색*을 의미합니다. 이제 ``<a>` 태그 안에 있는 <span> 태그를 검색하고 싶다고 가정합니다. 다음과 같이 할 수 있습니다:

//h:a/h:span    (Selects <span> tags inside <a> tags)

문서의 특정 수준에서 태그를 검색하려면 접두사를 변경하세요:

/h:body/h:div/h:p (Selects <p> tags that are children of <div> tags that are
             children of the <body> tag)

이것은 sample_ebook`에서 ``<p>A very short e-book to demonstrate the use of XPath.</p>``와만 일치하며 다른 ``<p>` 태그와는 일치하지 않습니다. 위 예시의 h: 접두사는 XHTML 태그와 일치시키기 위해 필요합니다.这是因为 내부적으로 calibre는 모든 콘텐츠를 XHTML로 표현하기 때문입니다. XHTML에서 태그는 *네임스페이스*를 가지며, ``h:``는 HTML 태그의 네임스페이스 접두사입니다.

이제 <h1>``과 ``<h2> 태그를 모두 선택하고 싶다고 가정합니다. 그렇게 하려면 *술어(predicate)*라는 XPath 구문이 필요합니다. :dfn:`술어`는 태그를 선택하는 데 사용되는 간단한 테스트입니다. 테스트는 임의로 강력할 수 있으며 이 튜토리얼이 진행됨에 따라 더 강력한 예시를 보게 될 것입니다. 술어는 테스트 표현식을 대괄호로 감싸서 만듭니다:

//*[name()='h1' or name()='h2']

이 XPath 표현식에는 여러 가지 새로운 기능이 있습니다. 첫 번째는 와일드카드 *``의 사용입니다. *모든 태그와 일치*를 의미합니다. 이제 테스트 표현식 ``name()='h1' or name()='h2'``를 살펴보세요. :term:`name()`은 *내장 함수*의 예시입니다. 태그의 이름으로 평가됩니다. 따라서 이를 사용하여 이름이 `h1`이거나 `h2`인 태그를 선택할 있습니다. :term:`name()` 함수는 네임스페이스를 무시하므로 ``h: 접두사가 필요하지 않습니다. XPath에는 여러 유용한 내장 함수가 있습니다. 이 튜토리얼에서 몇 가지를 더 소개하겠습니다.

속성으로 선택

태그의 속성을 기반으로 태그를 선택하려면 술어를 사용해야 합니다:

//*[@style]              (Select all tags that have a style attribute)
//*[@class="chapter"]    (Select all tags that have class="chapter")
//h:h1[@class="bookTitle"] (Select all h1 tags that have class="bookTitle")

여기서 @ 연산자는 태그의 속성을 참조합니다. XPath 내장 함수 중 일부를 사용하여 속성 값에 대해 더 정교한 일치를 수행할 수 있습니다.

태그 내용으로 선택

XPath를 사용하면 태그가 포함하고 있는 텍스트를 기반으로 태그를 선택할 수도 있습니다. 가장 좋은 방법은 내장 함수 :term:`re:test()`를 통해 *정규 표현식*의 강력함을 활용하는 것입니다:

//h:h2[re:test(., 'chapter|section', 'i')] (Selects <h2> tags that contain the words chapter or
                                          section)

여기서 . 연산자는 태그의 내용을 참조하며, @ 연산자가 태그의 속성을 참조하는 것과 같습니다.

샘플 전자책

<html>
    <head>
        <title>A very short e-book</title>
        <meta name="charset" value="utf-8" />
    </head>
    <body>
        <h1 class="bookTitle">A very short e-book</h1>
        <p style="text-align:right">Written by Kovid Goyal</p>
        <div class="introduction">
            <p>A very short e-book to demonstrate the use of XPath.</p>
        </div>

        <h2 class="chapter">Chapter One</h2>
        <p>This is a truly fascinating chapter.</p>

        <h2 class="chapter">Chapter Two</h2>
        <p>A worthy continuation of a fine tradition.</p>
    </body>
</html>

XPath 내장 함수

name()

현재 태그의 이름입니다.

contains()

``contains(s1, s2)``는 s1이 s2를 포함하면 `true`를 반환합니다.

re:test()

``re:test(src, pattern, flags)``는 문자열 `src`가 정규 표현식 `pattern`과 일치하면 `true`를 반환합니다. 특히 유용한 플래그는 ``i``이며, 대소문자를 구분하지 않고 일치시킵니다. 정규 표현식 구문에 대한 좋은 입문 자료는 `regexp 구문 <https://docs.python.org/library/re.html>`_에서 확인할 수 있습니다.