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>

Заметки:

  1. Я пытался сделать все это с позиционированием оси, я хотел избежать использования @id если бы я мог.

  2. OxygenXML воспитывает The descendant axis starting at a text node will never select anything предупреждение. Веб-скрипка не делает. Любопытно.

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