Возвращение номеров страниц для набора элементов (оптимизация для XSLT 1.0/msxsl)
Это не столько "как сделать ххх", сколько "как оптимально сделать ххх?" (действительно надеясь, что вызов плавает на лодке Димитра...)
Все следующее усложняется ограничением процессора XSL (msxsl - в основном XSLT 1.0 с набором функций-узлов (), replaces() и match ()).
Я генерирую некоторые метаданные из определенных элементов в книге - скажем, главы и элементы div[title] (чтобы немного упростить нашу модель данных).
Номера страниц в книге задаются инструкциями обработки в узлах смешанного текста, которые могут выглядеть следующим образом:
<?Page pageId="256"?>
Номер страницы, с которой должен быть связан мой элемент, будет либо первым потомком (в случае, когда разрыв страницы - это, по сути, первая часть содержимого, скажем, в главе (т. Е. Глава начинается с новой страницы)), или же первая предшествующая:: инструкция обработки ('Страница').
Давайте составим образец документа:
<?xml version="1.0" encoding="UTF-8"?>
<book>
<chapter>
<title><?Page pageId="1"?>Chapter I</title>
<div>
<p>Introduction to Chapter</p>
<p>Second paragraph <?Page pageId="2"?>of introduction</p>
</div>
<div>
<title>Section I</title>
<p>A paragraph</p>
<p>Another paragraph<?Page pageID="3"?></p>
</div>
</chapter>
<chapter>
<title><?Page pageId="4"?>Chapter II</title>
<div>
<p>Introduction to Chapter</p>
<p>...</p>
</div>
</chapter>
</book>
(обратите внимание, что хотя каждая глава здесь начинается на новой странице, мы, как правило, не можем этого гарантировать. В конце главы 1 есть пустая страница, которую мы обычно видим).
Я хочу получить некоторую информацию, подобную этой (я хорошо знаком с основами XSLT, мы заинтересованы в выборе номеров страниц):
<meta>
<meta>
<field type="title">Chapter I</field>
<field type="page">1</field>
<meta>
<field type="title">Section I</field>
<field type="page">2</field>
</meta>
</meta>
<meta>
<field type="title">Chapter II</field>
<field type="page">4</field>
</meta>
</meta>
Я могу делать разные вещи, используя xsl: когда операторы и ось потомков, чтобы решить, какой номер страницы подходит, но я бы предпочел сделать что-то умное, сопоставляя инструкции обработки, поскольку в настоящее время использование оси потомков в больших книгах делает вещи более подходящими. слишком медленный, чтобы его можно было использовать. Ключи были бы хорошими, но все усложняется тем, что они не могут использовать ни переменные, ни другие ключи в атрибутах @use или @match (и, аналогично, не могут использовать конструкторы последовательностей).
В настоящее время элементы, для которых я заинтересован в поиске номеров страниц, определены в ключе (данные реального мира гораздо более сложны), например:
<xsl:key name="auth" match="chapter|div[title]" use="generate-id()"/>
Любые предложения или указатели с благодарностью получены!
1 ответ
Вот решение с использованием ключей, которое может быть эффективным:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kPage"
match="chapter/title/processing-instruction('Page')"
use="generate-id(..)"/>
<xsl:key name="kPage"
match="processing-instruction('Page')"
use="generate-id(following::div[title][1]/title)"/>
<xsl:template match="*">
<xsl:apply-templates select=
"*[1]|following-sibling::*[1]"/>
</xsl:template>
<xsl:template match="chapter/title[1] | div/title[1]">
<meta>
<field type="title"><xsl:value-of select="."/></field>
<field type="page">
<xsl:variable name="vPiText"
select="key('kPage', generate-id())[last()]"/>
<xsl:value-of select=
"translate($vPiText,
translate($vPiText, '01234567890', ''),
''
)"/>
</field>
<xsl:apply-templates select="*[1]|following-sibling::*[1]"/>
</meta>
</xsl:template>
</xsl:stylesheet>
когда это преобразование применяется к предоставленному документу XML:
<book>
<chapter>
<title>
<?Page pageId="1"?>Chapter I</title>
<div>
<p>Introduction to Chapter</p>
<p>Second paragraph
<?Page pageId="2"?>of introduction</p>
</div>
<div>
<title>Section I</title>
<p>A paragraph</p>
<p>Another paragraph
<?Page pageID="3"?></p>
</div>
</chapter>
<chapter>
<title>
<?Page pageId="4"?>Chapter II</title>
<div>
<p>Introduction to Chapter</p>
<p>...</p>
</div>
</chapter>
</book>
желаемый, правильный результат получается:
<meta>
<field type="title">Chapter I</field>
<field type="page">1</field>
<meta>
<field type="title">Section I</field>
<field type="page">2</field>
</meta>
</meta>
<meta>
<field type="title">Chapter II</field>
<field type="page">4</field>
</meta>