选择整个xml文档中空<cb>元素之间的所有节点,用div

时间:2016-06-14 00:18:09

标签: xml xslt xpath xslt-1.0 tei

我正在使用XSLT将XML(tei)文档转换为HTML。 目标是创建可以设置为显示为固定列的div。

在文档中,列开头由2个空元素(里程碑和cb)表示。 &#34;里程碑&#34;表示文本流中的列数现在等于n属性。 &#34; CB&#34;标记列的开头,其n属性以从左到右的顺序指示其顺序。 &#34; cb&#34;标签并不总是兄弟姐妹。

示例xml:

<p>
  <milestone unit="column" n="2"/>
  <cb n="1"/>
  M. Dudley
  <lb/>
  H. E. Ernshimer
  <lb/>
  M. M. Cash
  <lb/>
  John Wheatly
  <lb/>
  Jno W. Cash
  <lb/>
  <cb n="2"/>
  R. L. Wilson
  <lb/>
  R. B. Ratliff L.C.C.
  <lb/>
  G. D Watkins Clk
  <lb/>
  A. C. Mayes
  <lb/>
  <pb/>
</p>
<p>
   <note place="left margin">Jury 1863 Nov.</note>
   <lb/>
   <cb n="1"/>
   D C Mitchenssson
   <lb/>
   A. W. Forde, Tm P
   <lb/>
   L S Thomson
   <lb/>
   Louis Martin
   <hi rend="sup">c</hi>
   Casslin
   <lb/>
   E. M. Stevens
   <lb />
   <cb n="2"/>
   O Ross Baker Clk Caldwell County Court
   <lb/>
   N. Jones
   <lb/>
   S. W. M
   <milestone unit="column" n="1"/>
   <pb/>
   <lb/>
   John Garrett
</p>

下面的结果。 div等于其前一个里程碑的属性:

<div class="column 2">
    M. Dudley<br />
    H. E. Ernshimer<br />
    M. M. Cash<br />
    John Wheatly<br />
    Jno W. Cash<br />
    ...
</div>
<div class="column 2">
    R. L. Wilson<br />
    R. B. Ratliff L.C.C.<br />
    G. D Watkins Clk<br />
    A. C. Mayes<br />
    Jas Crenshaw<br />
</div>

如何抓取每对cb标签之间的所有内容,并将内容包装在包含div中?我尝试过的所有内容都会产生一系列嵌套的div。

2 个答案:

答案 0 :(得分:0)

  

如何在每对cb标签之间抓取所有内容

我没有看到你有包含列内容的cb个标签 - 只有顶部的cb元素。< / p>

IIUC,你想做这样的事情:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="txt-by-col" match="text()" use="generate-id(preceding-sibling::cb[1])" />

<xsl:template match="/">
    <root>
        <xsl:for-each select="//cb">
            <div class="column {preceding::milestone[1]/@n}">
                <xsl:for-each select="key('txt-by-col', generate-id())">
                    <xsl:value-of select="." />
                    <br/>
                 </xsl:for-each>    
            </div>
        </xsl:for-each>
    </root>
</xsl:template>

</xsl:stylesheet>

这并不是假设列的所有文本节点都是前导cb元素的兄弟节点。

答案 1 :(得分:0)

我提出了一个可行的解决方案。可能不是很优雅,但它符合我的目的。我将在此发布,以防将来对其他人有用。

<!-- add a white space in empty milestone so it doesn't wrap around other elements -->
<xsl:template match="tei:milestone">
  <xsl:variable name="milenum" select="@n" />
  <milestone>
    <xsl:attribute name="n">
       <xsl:value-of select="$milenum" />
    </xsl:attribute>
    <xsl:text> </xsl:text>
  </milestone>
</xsl:template>

<!-- add a white space in empty cb so it doesn't wrap around other elements -->
<xsl:template match="tei:cb">
   <xsl:variable name="num" select="@n" />
   <cb>
      <xsl:attribute name="n">
         <xsl:value-of select="$num" />
      </xsl:attribute>
      <xsl:text> </xsl:text>
   </cb>
</xsl:template>

<!-- wrap content following cb elements in a div, with a class indicating the number of columns in the preceding milestone n attribute (if milestone n=2, then div class=column1of2 or div class=column2of2) -->
<xsl:template match="tei:p[tei:cb]">
    <!-- to print text before the first milestone -->
    <xsl:apply-templates select="node()[not(preceding::tei:milestone)]" />
    <xsl:for-each select="tei:cb">
      <xsl:variable name="count" select="position()" />
      <div>
         <xsl:variable name="numberofcolumns" select="preceding::tei:milestone[1]/@n" />
         <xsl:variable name="n" select="@n" />
         <xsl:attribute name="class">
           <xsl:text>column</xsl:text>
           <xsl:value-of select="$n" />
           <xsl:text>of</xsl:text>
           <xsl:value-of select="$numberofcolumns" />
         </xsl:attribute>
         <xsl:apply-templates select="following-sibling::node()[preceding-sibling::tei:cb[1][@n=$n] and count(preceding-sibling::tei:cb)=$count and preceding::tei:milestone[1][@n>1] and not(self::tei:milestone)]" />
       </div>
     </xsl:for-each>
 </xsl:template>

输出:

<milestone n="2"> </milestone>
<div class="column1of2">
</div>
<div class="column2of2">
</div>
<div class="column1of2">
</div>
<div class="column2of2">
</div>

现在我从@ michael.hor257k看到了答案,我会用他的方法简化这段代码。