XSLT 2.0, Xpath, DITA: выбрать все содержимое между двумя элементами с одинаковым именем
Я беру плоский источник HTML и преобразовываю его в иерархические файлы DITA с их соответствующими .ditamap
,
Это возиться, но, конечно, <result-document>
не будет работать там.
редактировать: это перефразировано к меньшему более краткому отражению проблемы.
Я рядом Это представляет мой источник. Это выглядит сложным, но не так: в результате документы будут все между <concept>
элементы.. независимо от вложенности / сложности в них.
<!--
this is an interim file while converting flat html
to a hierarchical DITA structure
-->
<concepts text-title="Manual" id="manual">
<concept id="chapter1">
<title>Chapter 1</title>
<conbody>
<p>contents in body will</p>
<lq><i>vary</i> widely</lq>
<concept id="subchapter1-1">
<title>Subchapter 1</title>
<conbody>
<table>table</table>
<lq>foo</lq>
</conbody>
</concept>
</conbody>
</concept>
<concept id="chapter2">
<title>Chapter 2</title>
<conbody>
<table>table</table>
<lq>foo <pre>code</pre></lq>
</conbody>
<concept id="subchapter2-1">
<title>Subchapter 1</title>
<conbody>
<table>table</table>
<lq><b>foo</b></lq>
</conbody>
</concept>
</concept>
</concepts>
Это мой xslt, я сделал комментарии в области, где моя сложность.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs mf"
xmlns:mf="http://example.org/mf"
version="2.0">
<xsl:output
method="xml"
omit-xml-declaration="no"
doctype-system="../dtd/technicalContent/dtd/map.dtd"
doctype-public="-//OASIS//DTD DITA Map//EN"
encoding="UTF-8"
indent="yes"/>
<xsl:strip-space elements="*"/>
<!--
Source: monolithic XML file containing many nested <concept> topics
Transform outcomes:
1. Transform of source will create a DITA <map><topicref>
2. A <result-document> will write out each <concept> as a singular file
-->
<xsl:template match="/">
<map
title="{/concepts/@text-title}"
id="{/concepts/@id}">
<xsl:apply-templates/>
</map>
</xsl:template>
<xsl:template match="text()"/>
<xsl:template match="concepts">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="concept">
<xsl:variable name="path-filename" select="concat('/home/mike/dita/prodrun/',@id,'.dita')"/>
<!-- transform source to make the DITA <map> -->
<topicref href="{$path-filename}" type="concept">
<xsl:apply-templates/>
</topicref>
<!-- write out this <concept> to the file system -->
<xsl:result-document
method="xml"
encoding="UTF-8"
omit-xml-declaration="no"
indent="yes"
doctype-system="../../dtd/technicalContent/dtd/concept.dtd"
doctype-public="-//OASIS//DTD DITA Concept//EN"
href="{$path-filename}">
<concept id="new foo will be added here">
<!--
Below is one of my efforts. I need to select ALL, to stopping short of next <concept>
I also tried <for-each-group's .. to no avail
-->
<xsl:copy-of select="descendant::*[not(self::*)][preceding::concept[1]]"/>
</concept>
</xsl:result-document>
</xsl:template>
В конце у меня будет ditamap
эта часть работает. У меня также будет четыре таких файла в моей файловой системе:
<concept id="t20">
<title>Chapter 1</title>
<conbody>
<p>contents in body will</p>
<lq><i>vary</i> widely</lq>
</conbody>
</concept>
<concept id="subchapter1-1">
<title>Subchapter 1</title>
<conbody>
<table>table</table>
<lq>foo</lq>
</conbody>
</concept>
<concept id="chapter2">
<title>Chapter 2</title>
<conbody>
<table>table</table>
<lq>foo <pre>code</pre></lq>
</conbody>
</concept>
<concept id="subchapter2-1">
<title>Subchapter 1</title>
<conbody>
<table>table</table>
<lq><b>foo</b></lq>
</conbody>
</concept>
FWIW: я работаю в OxygenXML, но я буду запускать это регулярно с Saxon из командной строки.
Sidenote: это действительно открыло мне глаза на полезность doctypes, пространств имен и проверки на лету.
3 ответа
Попробуй это, надо вместо этого делать работу;)
<!--concept id="new foo will be added here"-->
<concept>
<xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
<title>
<xsl:copy-of select="title/@*|title/node()"/>
</title>
<conbody>
<xsl:copy-of select="conbody/@*|conbody/node()"/>
</conbody>
<!--
Below is one of my efforts. I need to select ALL, to stopping short of next <concept>
I also tried <for-each-group's .. to no avail
-->
<!--xsl:copy-of select="descendant::*[not(self::*)][preceding::concept[1]]"/-->
</concept>
Об этом замечании:
OxygenXML поднимает ось потомка, начинающуюся с текстового узла, никогда не выберет ничего, предупреждающего. Веб-скрипка не делает. Любопытно.
Кислород проверяет XSLT с помощью процессора Saxon XSLT. Это означает, что пока XPath в таблице стилей 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:output
method="xml"
omit-xml-declaration="yes"
encoding="UTF-8"
indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="concept"/>
<!--
The xpath in the <for-each> below:
..give me the descendants of this <concept>..
..excluding descendants that may be in
descendant 'nested' <concept>'s
-->
<xsl:template match="concepts">
<documents>
<xsl:for-each select="//concept">
<simulated-result-document>
<xsl:for-each
select="node() | text()
[descendant::*]
[not(descendant::concept[self::concept])]">
<xsl:apply-templates select="."/>
</xsl:for-each>
</simulated-result-document>
</xsl:for-each>
</documents>
</xsl:template>
Исходный XML:
<concepts>
<concept id="1">
<title>Title 1 - General</title>
Test unbound text here.
<p>In determining the..</p>
<p>Words describing the singular..</p>
<p>Words describing the plural..</p>
<concept id="2">
<title>Chapter 2 - Rules</title>
<p>Words implying the masculine gender..</p>
<p>Words implying the feminine..</p>
<p>words in the present tense..</p>
<concept id="3">
<title>§ 1. Gender</title>
<p>Male.. text text text </p>
<p>Female.. text text text </p>
</concept>
<concept id="4">
<title>§ 2. Jurisdiction</title>
<p>Time.. jurisdiction text text text</p>
<p>Place.. jurisdiction text text text</p>
<p>Person.. jurisdiction text text text</p>
<concept id="4.1">
<title>§ 2.1 Status</title>
<p>Citizen.. text text text </p>
<p>Stateless.. text text text </p>
</concept>
</concept>
</concept>
<concept id="5">
<title>Chapter 2 - Authority</title>
<p>Time.. authority text text text</p>
<p>Place.. authority text text text</p>
<concept id="6">
<title>§ 1. Determination</title>
<p>Time.. Universal Coordinated Time..<b>UTC</b></p>
<p>Place.. Cartesian Coordinates</p>
</concept>
<concept id="7">
<title>§ 2. Foo</title>
<p>signatures convey..</p>
<p>oath is ..</p>
<p>utterances are ..</p>
</concept>
</concept>
</concept>
Заметки:
Я пытался сделать все это с позиционированием оси, я хотел избежать использования
@id
если бы я мог.OxygenXML воспитывает
The descendant axis starting at a text node will never select anything
предупреждение. Веб-скрипка не делает. Любопытно.