2016-06-24 228 views
2

我與一個非常具體的事情 - 生成用於epub的NCX文件糾纏在一起。問題在於每個navPoint元素的playOrder屬性,因爲數字通常只是簡單地增加而沒有任何嵌套的重要性。另一方面,該文件是通過迭代嵌套元素自然生成的(它拒絕簡單使用at $count計算樣式)。我試圖通過直接在數組數組上迭代生成這個,我試圖從準備好的toc文件中生成它(可能更容易,因爲我迭代了一個節點,而不是數組)。問題是一樣的。 NCX文件的如何在XQuery中爲NCX文件(用於epub)生成正確的playOrder?

樣品部分:

<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1"> 
    <head> 
     <meta name="dtb:uid" content=""/> 
     <meta name="dtb:depth" content="1"/> 
     <meta name="dtb:totalPageCount" content="0"/> 
     <meta name="dtb:maxPageNumber" content="0"/> 
    </head> 
    <docTitle> 
     <text/> 
    </docTitle> 
    <navMap> 
     <navPoint id="title-page" playOrder="1"> 
      <navLabel> 
       <text>Title Page</text> 
      </navLabel> 
      <content src="title-page.xhtml"/> 
     </navPoint> 
     <navPoint id="chapter-1.xhtml#anch1lev1" playOrder="@@@"> 
      <navLabel> 
       <text>ÚVOD</text> 
      </navLabel> 
      <content src="chapter-1.xhtml#anch1lev1"/> 
      <navPoint id="chapter-1.xhtml#anch2lev1" playOrder="@@@"> 
       <navLabel> 
        <text>Přehled bádání nad nálezy terry sigillaty v Čechách</text> 
       </navLabel> 
       <content src="chapter-1.xhtml#anch2lev1"/> 
      </navPoint> 
      <navPoint id="chapter-1.xhtml#anch2lev2" playOrder="@@@"> 
       <navLabel> 
        <text>Poválečné bádání nad nálezy terry sigillaty v evropském barbariku</text> 
       </navLabel> 
       <content src="chapter-1.xhtml#anch2lev2"/> 
      </navPoint> 
      <navPoint id="chapter-1.xhtml#anch2lev3" playOrder="@@@"> 
       <navLabel> 
        <text>Terminologie a tvarová klasifikace</text> 
       </navLabel> 
       <content src="chapter-1.xhtml#anch2lev3"/> 
      </navPoint> 
     </navPoint> 
     <navPoint id="chapter-2.xhtml#anch1lev1" playOrder="@@@"> 
      <navLabel> 
       <text>KATALOG</text> 
      </navLabel> 
      <content src="chapter-2.xhtml#anch1lev1"/> 
      <navPoint id="chapter-2.xhtml#anch2lev1" playOrder="@@@"> 
       <navLabel> 
        <text>Struktura a metodické pojetí katalogu</text> 
       </navLabel> 
       <content src="chapter-2.xhtml#anch2lev1"/> 
      </navPoint> 
      <navPoint id="chapter-2.xhtml#anch2lev2" playOrder="@@@"> 
       <navLabel> 

在這裏,我有playOrder屬性只是作爲一個佔位符。有沒有簡單的方法如何用簡單增加的計數器(每navPoint)代替@@@?我嘗試過typeswitch(無法使其工作)並詳盡計算標題的前一級別,但它的工作原理是極其笨拙並且隨着標題級別的增加而變慢,並且由於xpath軸略有變化,因此在文檔間非常不穩定。我需要一個簡單,防彈的方法。我想很多先前的水平計數是不正確的選擇。

回答

1

在自己接近這個問題時,我可能會嘗試在首次創建NCX文件時生成正確的值。但是,如果面臨的挑戰是如何在一個文件中修復playOrder屬性,其中的值充滿了空值,虛擬屬性或其他不正確的屬性,我可以考慮兩種技術:使用XQuery類型切換表達式遍歷文檔中的所有節點並交換所需的值,或者使用XQuery Update來手術更新值。在下面的每個示例中,兩者都採用相同的方法:使用ancestorpreceding XPath軸計算playOrder屬性的值。注意:我對XML示例的唯一更改是關閉最終元素,以使其格式良好。

更新:在我的第一個版本中,我誤刪了ancestor軸計數,導致不正確的值。我忘記了preceding軸不包含軸ancestor。從我最喜歡的XPath軸圖表中可以清楚看到,https://our.umbraco.org/media/upload/0562fd58-c6db-4fa8-a432-68b28f11c3f2/rs/7x1B0.gif

xquery version "3.0"; 

declare namespace ncx="http://www.daisy.org/z3986/2005/ncx/"; 

declare function local:fix-playorder($nodes as item()*) { 
    for $node in $nodes 
    return 
     typeswitch ($node) 
      case element(ncx:navPoint) return 
       <navPoint xmlns="http://www.daisy.org/z3986/2005/ncx/">{ 
        $node/@*[not(name(.) = 'playOrder')], 
        attribute playOrder { count($node/ancestor::ncx:navPoint) + count($node/preceding::ncx:navPoint) + 1 }, 
        local:fix-playorder($node/node()) 
       }</navPoint> 
      case element() return 
       element {node-name($node)} {$node/@*, local:fix-playorder($node/node())} 
      default return 
       $node 
}; 

let $ncx := 
    <ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1"> 
     <head> 
      <meta name="dtb:uid" content=""/> 
      <meta name="dtb:depth" content="1"/> 
      <meta name="dtb:totalPageCount" content="0"/> 
      <meta name="dtb:maxPageNumber" content="0"/> 
     </head> 
     <docTitle> 
      <text/> 
     </docTitle> 
     <navMap> 
      <navPoint id="title-page" playOrder="1"> 
       <navLabel> 
        <text>Title Page</text> 
       </navLabel> 
       <content src="title-page.xhtml"/> 
      </navPoint> 
      <navPoint id="chapter-1.xhtml#anch1lev1" playOrder="@@@"> 
       <navLabel> 
        <text>ÚVOD</text> 
       </navLabel> 
       <content src="chapter-1.xhtml#anch1lev1"/> 
       <navPoint id="chapter-1.xhtml#anch2lev1" playOrder="@@@"> 
        <navLabel> 
         <text>Přehled bádání nad nálezy terry sigillaty v Čechách</text> 
        </navLabel> 
        <content src="chapter-1.xhtml#anch2lev1"/> 
       </navPoint> 
       <navPoint id="chapter-1.xhtml#anch2lev2" playOrder="@@@"> 
        <navLabel> 
         <text>Poválečné bádání nad nálezy terry sigillaty v evropském barbariku</text> 
        </navLabel> 
        <content src="chapter-1.xhtml#anch2lev2"/> 
       </navPoint> 
       <navPoint id="chapter-1.xhtml#anch2lev3" playOrder="@@@"> 
        <navLabel> 
         <text>Terminologie a tvarová klasifikace</text> 
        </navLabel> 
        <content src="chapter-1.xhtml#anch2lev3"/> 
       </navPoint> 
      </navPoint> 
      <navPoint id="chapter-2.xhtml#anch1lev1" playOrder="@@@"> 
       <navLabel> 
        <text>KATALOG</text> 
       </navLabel> 
       <content src="chapter-2.xhtml#anch1lev1"/> 
       <navPoint id="chapter-2.xhtml#anch2lev1" playOrder="@@@"> 
        <navLabel> 
         <text>Struktura a metodické pojetí katalogu</text> 
        </navLabel> 
        <content src="chapter-2.xhtml#anch2lev1"/> 
       </navPoint> 
       <navPoint id="chapter-2.xhtml#anch2lev2" playOrder="@@@"> 
        <navLabel/> 
       </navPoint> 
      </navPoint> 
     </navMap> 
    </ncx> 
return 
    local:fix-playorder($ncx) 

結果:

<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1"> 
    <head> 
     <meta name="dtb:uid" content=""/> 
     <meta name="dtb:depth" content="1"/> 
     <meta name="dtb:totalPageCount" content="0"/> 
     <meta name="dtb:maxPageNumber" content="0"/> 
    </head> 
    <docTitle> 
     <text/> 
    </docTitle> 
    <navMap> 
     <navPoint id="title-page" playOrder="1"> 
      <navLabel> 
       <text>Title Page</text> 
      </navLabel> 
      <content src="title-page.xhtml"/> 
     </navPoint> 
     <navPoint id="chapter-1.xhtml#anch1lev1" playOrder="2"> 
      <navLabel> 
       <text>ÚVOD</text> 
      </navLabel> 
      <content src="chapter-1.xhtml#anch1lev1"/> 
      <navPoint id="chapter-1.xhtml#anch2lev1" playOrder="3"> 
       <navLabel> 
        <text>Přehled bádání nad nálezy terry sigillaty v Čechách</text> 
       </navLabel> 
       <content src="chapter-1.xhtml#anch2lev1"/> 
      </navPoint> 
      <navPoint id="chapter-1.xhtml#anch2lev2" playOrder="4"> 
       <navLabel> 
        <text>Poválečné bádání nad nálezy terry sigillaty v evropském barbariku</text> 
       </navLabel> 
       <content src="chapter-1.xhtml#anch2lev2"/> 
      </navPoint> 
      <navPoint id="chapter-1.xhtml#anch2lev3" playOrder="5"> 
       <navLabel> 
        <text>Terminologie a tvarová klasifikace</text> 
       </navLabel> 
       <content src="chapter-1.xhtml#anch2lev3"/> 
      </navPoint> 
     </navPoint> 
     <navPoint id="chapter-2.xhtml#anch1lev1" playOrder="6"> 
      <navLabel> 
       <text>KATALOG</text> 
      </navLabel> 
      <content src="chapter-2.xhtml#anch1lev1"/> 
      <navPoint id="chapter-2.xhtml#anch2lev1" playOrder="7"> 
       <navLabel> 
        <text>Struktura a metodické pojetí katalogu</text> 
       </navLabel> 
       <content src="chapter-2.xhtml#anch2lev1"/> 
      </navPoint> 
      <navPoint id="chapter-2.xhtml#anch2lev2" playOrder="8"> 
       <navLabel/> 
      </navPoint> 
     </navPoint> 
    </navMap> 
</ncx> 

一個XQuery更新的方法將使用相同的preceding軸線技術。我的例子是eXist的XQuery更新實現,它要求文件存儲在數據庫中。結果文件與上述結果相同。

xquery version "3.0"; 

declare namespace ncx="http://www.daisy.org/z3986/2005/ncx/"; 

let $ncx := 
    <ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1"> 
     <head> 
      <meta name="dtb:uid" content=""/> 
      <meta name="dtb:depth" content="1"/> 
      <meta name="dtb:totalPageCount" content="0"/> 
      <meta name="dtb:maxPageNumber" content="0"/> 
     </head> 
     <docTitle> 
      <text/> 
     </docTitle> 
     <navMap> 
      <navPoint id="title-page" playOrder="1"> 
       <navLabel> 
        <text>Title Page</text> 
       </navLabel> 
       <content src="title-page.xhtml"/> 
      </navPoint> 
      <navPoint id="chapter-1.xhtml#anch1lev1" playOrder="@@@"> 
       <navLabel> 
        <text>ÚVOD</text> 
       </navLabel> 
       <content src="chapter-1.xhtml#anch1lev1"/> 
       <navPoint id="chapter-1.xhtml#anch2lev1" playOrder="@@@"> 
        <navLabel> 
         <text>Přehled bádání nad nálezy terry sigillaty v Čechách</text> 
        </navLabel> 
        <content src="chapter-1.xhtml#anch2lev1"/> 
       </navPoint> 
       <navPoint id="chapter-1.xhtml#anch2lev2" playOrder="@@@"> 
        <navLabel> 
         <text>Poválečné bádání nad nálezy terry sigillaty v evropském barbariku</text> 
        </navLabel> 
        <content src="chapter-1.xhtml#anch2lev2"/> 
       </navPoint> 
       <navPoint id="chapter-1.xhtml#anch2lev3" playOrder="@@@"> 
        <navLabel> 
         <text>Terminologie a tvarová klasifikace</text> 
        </navLabel> 
        <content src="chapter-1.xhtml#anch2lev3"/> 
       </navPoint> 
      </navPoint> 
      <navPoint id="chapter-2.xhtml#anch1lev1" playOrder="@@@"> 
       <navLabel> 
        <text>KATALOG</text> 
       </navLabel> 
       <content src="chapter-2.xhtml#anch1lev1"/> 
       <navPoint id="chapter-2.xhtml#anch2lev1" playOrder="@@@"> 
        <navLabel> 
         <text>Struktura a metodické pojetí katalogu</text> 
        </navLabel> 
        <content src="chapter-2.xhtml#anch2lev1"/> 
       </navPoint> 
       <navPoint id="chapter-2.xhtml#anch2lev2" playOrder="@@@"> 
        <navLabel/> 
       </navPoint> 
      </navPoint> 
     </navMap> 
    </ncx> 
let $store := xmldb:store('/db', 'test.ncx', $ncx) 
let $doc := doc('/db/test.ncx') 
for $navPoint in $doc//ncx:navPoint 
return 
    update value $navPoint/@playOrder with (count($node/ancestor::ncx:navPoint) + count($navPoint/preceding::ncx:navPoint) + 1) 
+0

XPath之一的替代方法是使用'index-of(// navPoints,$ navPoint)' – joewiz

+0

您的解決方案非常複雜,我必須將其標記爲答案。其實,我最終使用的解決方案只是'playOrder =「{count($ h1/preceding :: xhtml:li)+ 1}」''$ h1'是標題的變量,接下來它將是' $ h2'等等。爲了方便起見,我將添加另一個答案。 –

+0

這個圖很棒!我剛把它貼在我的LCD上! –

1

最後,解決方案對我而言非常簡單。我在收集epub的所有條目期間生成NCX文件(該文件在操作之前不存在)。對我來說,它可以從TOC文件生成它,這是在過程中的前面步驟中生成的。

用於TOC生成nav我使用:

<nav epub:type='toc'> 
    <ol>{ 
     for $sect in $chaps 
     let $name := replace($sect/@name, "OEBPS/", "") 
     return 
     for $one in $sect//xhtml:h1 
     return 
      <li> 
      <a href='{$name || '#' || $one/@id}'>{$one/text()[not(ancestor-or-self::xhtml:sup)]}</a>{ 
       if ($one/parent::*//xhtml:h2 and xs:integer($head-level) ge 2) then 
       <ol>{ 
        for $two in $one/parent::*//xhtml:h2 
        return 
         <li> 
         <a href='{$name || '#' || $two/@id}'>{$two//text()[not(ancestor-or-self::xhtml:sup)]}</a>{ 
          if ($two/parent::*//xhtml:h3 and xs:integer($head-level) ge 3) then 
          <ol>{ 
           for $three in $two/parent::*//xhtml:h3 
           return 
            <li> 
            … and so on. 

對於NCX的navMap我使用:

<navMap> 
    <navPoint id='title-page' playOrder='1'> 
    <navLabel> 
     <text>Title Page</text> 
    </navLabel> 
    <content src='title-page.xhtml'/> 
    </navPoint>{ 
    (: For every item in the $toc, I count preceding items + I add a number of parents, which are 
    items also (I guess to, it simply works! :) 
    for $h1 in $toc//xhtml:nav/xhtml:ol/xhtml:li 
    return 
     <navPoint id='{$h1/xhtml:a/@href}' playOrder='{count($h1/preceding::xhtml:li) + 2}'> 
     <navLabel> 
      <text>{$h1/xhtml:a/text()[not(ancestor-or-self::xhtml:sup)]}</text> 
     </navLabel> 
     <content src='{$h1/xhtml:a/@href}'/>{ 
      for $h2 in $h1/xhtml:ol/xhtml:li 
      return 
      <navPoint id='{$h2/xhtml:a/@href}' playOrder='{count($h2/preceding::xhtml:li) + 3}'> 
       <navLabel> 
       <text>{$h2/xhtml:a/text()[not(ancestor-or-self::xhtml:sup)]}</text> 
       </navLabel> 
       <content src='{$h2/xhtml:a/@href}'/> 
       … and so on. 

playOrder的特定的解決方案是:

playOrder='{count($h1/preceding::xhtml:li) + 2}' 

...這意味着我我正在計算TOC中包含的所有前面的標題+添加一個我指望的特定級別的棕褐色。它可能會被替換爲正確的父母計數,但這總是給我正確的結果。我無法計算父母/祖先的工作。