Вставка динамического тега xslt для элементов маркированного списка

Я только начал разбираться в XSLT и просматривать примеры W3school, чтобы решить новую задачу, которую дал мне мой работодатель.

У меня есть несколько файлов, которые мне нужно преобразовать с помощью XML-структур следующим образом.

     <tablecell bgcolor='white'>
<pardef id='16' leftmargin='0.2757in' list='bullet' keepwithnext='true' keeptogether='true'/>
        <par def='34'>
            <run>
                <font size='8pt' name='Verdana' pitch='variable' truetype='true'
     familyid='20' color='navy'/>Data in bullet point 1</run>
        </par>
        <par def='34'>
            <run>
                <font size='8pt' name='Verdana' pitch='variable' truetype='true'
     familyid='20' color='navy'/>Data in bullet point 2</run>
        </par>
        <par def='34'>
            <run>
                <font size='8pt' name='Verdana' pitch='variable' truetype='true'
     familyid='20' color='navy'/>Data in bullet point 3</run>
        </par>
        <par def='34'>
            <run>
                <font size='8pt' name='Verdana' pitch='variable' truetype='true'
     familyid='20' color='navy'/>Data in bullet point 4</run>
        </par>
    </tablecell>

То, что у меня есть для моего XSL для обработки xml, выглядит следующим образом.

    <xsl:template match="tablecell">
            <td>
                <xsl:copy-of select="@colspan" />
                <!--<xsl:value-of select="."/> -->
                <xsl:apply-templates select="table" />
                <xsl:apply-templates select="section" />
                <xsl:apply-templates select="par" />
                <xsl:apply-templates select="pardef" />
            </td>
    </xsl:template>

<xsl:template match="pardef">
        <xsl:if test="@list='bullet'">
            <ul>
                <xsl:apply-templates/>
         </xsl:if>
    </xsl:template>

    <xsl:template match="par">
            <p>
                <xsl:apply-templates select="run" />
            </p>
    </xsl:template>

    <xsl:template match="run">
            <li>
                <xsl:apply-templates select="run" />
            </li>
    </xsl:template>

Проблема, с которой я столкнулся, заключается в том, что я не уверен, как лучше всего динамически вставить закрывающий тег </ul> после последнего элемента <run> для создания маркеров. На практике в моих XML-файлах может быть любое количество тегов <run>, которые нужно преобразовать.

Здесь мне нужно что-то сделать с переменной и подсчитать количество элементов, а затем выполнить некоторую обработку на основе этой переменной?

Другая ситуация, в которой мне нужно руководство, заключается в том, что теги <run> должны быть окружены тегами <li> только в том случае, если они находятся в структуре pardef / par, где элемент pardef имеет атрибут list = 'bullet'.

Это результат, которого я пытаюсь достичь.

<p>
    <ul>
        <li>Data in bullet point 1</li>
        <li>Data in bullet point 2</li>
        <li>Data in bullet point 3</li>
        <li>Data in bullet point 4</li>
    </ul>  
</p>

Если бы вы могли указать мне правильное направление для двух вопросов, упомянутых выше, я был бы признателен.

Ваше здоровье


Не знаю, как продолжить этот существующий поток с дополнительными фрагментами кода, кроме редактирования существующего потока. Если вы дадите мне знать, как это сделать, было бы здорово.

Спасибо всем, кто помогал с этой проблемой. Кто-то ранее отвечал на этот пост с идеей использовать режимы, которые помогли мне продвинуться дальше. Сейчас у меня возникает следующий вопрос: если есть теги <par> с атрибутом def = 16, я хочу, чтобы он использовал шаблон mode = 'sixteen', в противном случае используйте общий базовый шаблон par, который очень просто использует теги <p></p>. Как этого добиться? Прямо сейчас я думаю об использовании оператора if, но будет ли это лучший способ сделать это?

Кроме того, означает ли приведенный ниже код, что элементы <par> потенциально обрабатываются дважды?

<xsl:template match="tablecell">
        <td>
            <!-- <xsl:copy-of select="@colspan" /> -->
            <xsl:apply-templates select="par" />
            <xsl:apply-templates select="table" />
            <xsl:apply-templates select="section" />

            <!-- Apply to par elements where attribute def=16 -->   
            <xsl:apply-templates select="par[@def='16']" mode='sixteen' />
        </td>
    </xsl:template>

    <!-- Template for par elements where attribute def=16 -->
    <xsl:template match="par" mode='sixteen'>
        <ul>
            <!-- Apply to any table elements -->    
            <xsl:apply-templates select="run" mode='bullet' />
        </ul>
    </xsl:template>

Это моя попытка, не уверен, что она правильная или лучшая.

  <xsl:template match="tablecell">
        <td>
            <xsl:choose>
                <xsl:when test="par[@def='16']">
                    <!-- Apply to par elements where attribute def=16 -->   
                    <xsl:apply-templates select="par[@def='16']" mode='sixteen' />

                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="par" />

                </xsl:otherwise>


            </xsl:choose>
<xsl:apply-templates select="table" />
                <xsl:apply-templates select="section" />
        </td>
    </xsl:template>

Лично я считаю, что w3schools часто бывает удобным сайтом для поиска вещей, которые вы забыли, потому что не часто ими пользуетесь, но это не лучший учебный сайт для людей, впервые изучающих язык. Также обратите внимание, что это не имеет ничего общего с W3C.

Michael Kay 26.10.2018 09:47
1
1
176
1

Ответы 1

Ключевой момент, который вам не хватает, заключается в том, что XSLT не создает начальный и конечный теги в выходных данных, он создает дерево узлов. Вы не можете записать половину узла в дерево. «Элемент буквального результата», такой как <ul> XXX </ul>, представляет собой отдельную инструкцию, которая (а) оценивает XXX для создания некоторого содержимого, и (b) создает узел элемента UL, к которому этот контент прикреплен. Вы должны думать о <ul></ul> как об одной инструкции, которая создает узел, а не как о инструкции, которая создает начальный тег, за которым следует инструкция, которая создает конечный тег.

Ваша проблема - это классическая проблема позиционной группировки. Фактически, это один из примеров, используемых в спецификации XSLT для инструкции xsl:for-each-group: найдите «Пример: группирование чередующихся последовательностей элементов» в https://www.w3.org/TR/xslt-30/#element-for-each-group. Обратите внимание, что для этой инструкции требуется XSLT 2.0 или XSLT 3.0. Во многих средах процессор XSLT по умолчанию по-прежнему поддерживает только XSLT 1.0. Решить эту проблему в версии 1.0 намного сложнее (это не невозможно, но это серьезная проблема для новичка в языке). Поэтому убедитесь, что вы используете процессор, поддерживающий версии 2.0 или 3.0.

Я прочитал статью, которую вы опубликовали, но нашел ее довольно запутанной с точки зрения использования. В другом сообщении, посвященном этому вопросу, предлагалось использовать режимы, которые сработали для меня, НО это вызывает связанный запрос.

spikycactus 29.10.2018 06:15

Сами по себе режимы не решат для вас проблему группировки, хотя могут быть частью решения. Боюсь, я не могу ничего предложить, кроме как продолжать читать, пока не поймете концепции. Есть несколько хороших книг по XSLT 2.0. Джени Теннисон - хорошее руководство для начинающих, моя книга направлена ​​на то, чтобы глубже изучить основные концепции и предоставить более исчерпывающий справочник по всем инструкциям.

Michael Kay 29.10.2018 13:19

Другие вопросы по теме