2013-12-04 1 views
2

Я пытаюсь сгенерировать pagelist, который состоит из конкатенации идентификатора различных divs (@chapter) | (@part) , Моя проблема связана с вложенными структурами: @part может содержать любое число @chapter. Я хочу только выбрать идентификатор последнего предка номера страницы в порядке документа.XSLT: Последовательность из более чем одного элемента не разрешена в качестве первого аргумента concat()

Ниже приведен фрагмент из XML:

<text> 
    <div class="part" id="s9781483352947.i870"> 
     <a class="page" id="pbr-31"/> 
     <h1 class="title">Part 1</h1> 
     <p>This is a paragraph.</p> 
     <p>This is a paragraph.</p> 
     <div class="chapter" id="s9781483352947.n3.i884"> 
      <a class="page" id="pbr-34"/> 
      <h1 class="title">Chapter 1</h1> 
      <p>This is a paragraph</p> 
     </div> 
    </div> 
</text> 

А ниже мой XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    exclude-result-prefixes="xs" 
    version="2.0"> 

    <xsl:template match="/"> 
    <xsl:element name="nav"> 
     <xsl:element name="h1"> 
      <xsl:value-of select="'Pages'"/> 
     </xsl:element> 
     <xsl:element name="ol"> 
      <xsl:apply-templates mode="pagelist" select="//a[@class='page']"/> 
     </xsl:element> 
    </xsl:element> 
    </xsl:template> 

    <xsl:template match="a[@class='page']" mode="pagelist"> 
     <xsl:variable name="html" select="concat(ancestor::div[@class='chapter'][1]/@id | ancestor::div[@class='part'][1]/@id,'.xhtml#page')"/> 
     <xsl:variable name="pagenumber" select="substring-after(@id,'-')"/> 
     <xsl:element name="li"> 
      <xsl:element name="a"> 
        <xsl:attribute name="href" select="concat($html,$pagenumber)"/> 
        <xsl:value-of select="substring-after(@id,'-')"/> 
       </xsl:element> 
     </xsl:element> 
    </xsl:template> 

</xsl:stylesheet> 

Однако я получаю сообщение об ошибке: последовательность более одного элемента не разрешено как первый аргумент concat(). Очевидно, что мой XPath выбирает несколько строк в первом аргументе из-за @part и @chapters. Как ограничить выбор первым предком класса = 'page'?

Это желательно Ouput для вышеуказанного образца:

<nav> 
    <h1>Pages</h1> 
    <ol> 
     <li> 
      <a href="s9781483352947.i870.xhtml#page31">31</a> 
     </li> 
     <li> 
      <a href="s9781483352947.n3.i884.xhtml#page34">34</a> 
     </li> 
    </ol> 
</nav> 

ответ

4

Прежде всего, символ трубы в Xpath не является «или», о котором вы думаете. Он объединяет два отдельных запроса и возвращает их как один набор узлов. Итак, что происходит, каждый из ваших запросов для глав и частей возвращает один элемент (атрибут @id первого узла), а затем его комбинированное возвращение узла с двумя узлами. Следовательно, у concat возникают проблемы.

Вы можете сделать:

(ancestor::div[@class='chapter'] | ancestor::div[@class='part'])[1]/@id 

Но было бы неправильно !! Поскольку это будет первое в комбинированной серии, но оно не объединит их в правильный порядок документа. Так было бы всегда получить главу, если она доступна, прежде чем получить часть.

Что вам нужно, а не так:

ancestor::div[@class='chapter' or @class='part'][1]/@id 

Я не уверен, почему вы используете concat на то, что вы уже concat ред. Как и в сторону, если вы concat ИНГ со строкой и сделать атрибут, you can just surround it in curly braces to make the XSLT shorter, как показано ниже:

<xsl:template match="a[@class='page']" mode="pagelist"> 
    <xsl:variable name="html" select="ancestor::div[@class='chapter' or @class='part'][1]/@id"/> 
    <xsl:variable name="pagenumber" select="substring-after(@id,'-')"/> 
    <li> 
     <a href="{$html}.xhtml#page{$pagenumber}"> 
      <xsl:value-of select="$pagenumber"/> 
     </a> 
    </li> 
</xsl:template> 

редактировать: Если вы хотите продолжать использовать xsl:attribute элементы, которые вы могли бы использовать CONCAT как в следующем шаблон:

<xsl:template match="a[@class='page']" mode="pagelist"> 
    <xsl:variable name="html" select="ancestor::div[@class='chapter' or @class='part'][1]/@id"/> 
    <xsl:variable name="pagenumber" select="substring-after(@id,'-')"/> 
    <li> 
     <a> 
      <xsl:attribute name="href"> 
       <xsl:value-of select="concat($html,'.xhtml#page',$pagenumber)"/> 
      </xsl:attribute> 
      <xsl:value-of select="$pagenumber"/> 
     </a> 
    </li> 
</xsl:template> 

Его немного более многословным, поэтому я предпочитаю inline attribute values.

+1

Благодарим вас за отличное объяснение! Также спасибо за отзыв на более короткий XSLT.Он не выглядит законным XPath, если я использую конструкцию с атрибутом select. Однако он отлично работает на самом элементе. – user2093335

+0

@ user2093335 Не беспокойтесь. Но что теперь не является законным Xpath? –

+0

Если я использую: - Получается ошибка в атрибуте xsl: select – user2093335

2

Я хотел бы предложить вам изменить вычисление переменной html к

<xsl:variable name="html" select="concat(ancestor::div[@class='chapter' or @class='part'][1]/@id, '.xhtml#page')"/> 

Перемещая чек на допустимом class в в скобках вы никогда не получите больше одного узла из выражения предка XPath.

Смежные вопросы