XPath-handledning

I den här handledning kommer du att få en lätt introduktion till XPath, ett frågespråk som kan användas för att välja godtyckliga delar av HTML dokument i calibre. XPath är en allmänt använd standard, och googla det kommer att ge en ton av information. Denna handledning, däremot fokuserar på att använda XPath för e-bok relaterade uppgifter som att hitta kapitelrubriker i ett ostrukturerad HTML-dokument.

Väljer efter etikettnamn

Den enklaste formen av val är att välja etikett efter namnet. Anta till exempel att du vill välja alla <h2> etiketter i ett dokument. XPath-förfråga till detta är helt enkelt:

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

Prefixet // betyder söka på alla nivåer i dokumentet. Anta nu att du vill söka efter <span> etiketter som är inne <a> etiketter. Detta kan uppnås med:

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

Om du vill söka efter etiketter på en viss nivå i dokumentet, ändrar prefixet:

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

Detta kommer bara matcha <p>En mycket kort e-bok för att demonstrera användningen av XPath.</p> i Exempel e-bok men inte någon annan av de andra <p> etiketterna. h: prefix i ovan exempel behövs för att passa XHTML-etiketter. Detta för att internt, calibre representerar allt innehåll som XHTML. I XHTML-etiketter finns en namnrymd, och h: är namnrymdsprefix för HTML-etiketter.

Anta nu att du vill välja både <h1> och <h2> etiketter. För att göra det behöver vi en XPath konstruktion som kallas predikat. En : dfn: ’predikat’ är helt enkelt ett test som används för att välja etiketter. Tester kan vara godtyckligt kraftfullt och som denna handledning fortskrider, kommer du att se mer kraftfulla exempel. Ett predikat skapas genom att innesluta test uttryck inom hakparenteser:

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

Det finns flera nya funktioner i detta XPath-uttryck. Den första är användningen av tecknet *. Det betyder matchar alla etiketter. Titta nu på prov uttrycket name()="h1" eller name()= 'h2'. name() är ett exempel på en inbyggd funktion. Den utvärderar endast namnet på etiketten. Så genom att använda det, kan vi välja etiketter vars namn är antingen h1 eller h2. Observera att name()-funktionen ignorerar namespaces, så att det inte finns något behov av h:-prefixet. XPath har flera användbara inbyggda funktioner. Några fler kommer att introduceras i den här guiden.

Väljer baserat på attribut

För att välja etiketter baserat på deras attribut, användning av predikat krävs:

//*[@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")

Här hänvisar @ operatören attributen för etiketten. Du kan använda en del av de XPath inbyggda funktioner _ att utföra mer avancerad matchning på attributvärden.

Väljer baserat på etikettinnehåll

Med hjälp av XPath kan du även välja etiketter som baseras på text de innehåller. Det bästa sättet att göra detta är att använda kraften i reguljära uttryck via den inbyggda funktionen: term:re:test():

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

Här hänvisar . operatör till innehållet i etiketten, precis som @ operatör avser dess attribut.

Exempel e-bok

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

Inbyggda XPath-funktioner

name()
Namnet på den aktuella etiketten.
contains()
contains(s1, s2) återger true om s1 innehåller s2.
re:test()
re:test(src, pattern, flags) återger true om strängen src matchar med det reguljära uttrycks mönster. En särskilt användbar flaggan är i, det gör matchning skiftlägesokänslig. En bra grund på syntaxen för reguljära uttryck finns på regexp syntax