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 내장 함수 중 일부를 사용하여 속성 값에 대해 더 정교한 일치를 수행할 수 있습니다.
참고
When XPath expressions are used for conversion options such as chapter
detection or the start reading at position, they are evaluated against the
input document, before calibre flattens the CSS. CSS flattening rewrites
class names, so the class names you see in the converted output (things like
calibre1) do not exist yet when your expression runs. Copy
class names from the input document, not from the converted book. If in
doubt, match on tag names and text content instead, as these are not changed
by the conversion.
태그 내용으로 선택¶
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>
