XSLT: Grouping by <div><head>

Viewed 23

I have an XML-document that contains several groups of

<div><head>some content</head>some more text and lbs etc. </div><div><head>some content</head> even more text etc. </div>

during edit, as I was not providing the structure in the post directly:

<TEI>
 <teiHeader>      
 <!--imagine this being a correct teiHeader, the document gets really long if I include the stuff  -->
   </teiHeader><standOff/>
<text>
<body>

<div><head facs="#facs_13_TextRegion_1624022854326_321">
            <pb facs="#facs_13" xml:id="img_0013" n="4v"/>            
            <lb facs="#facs_13_line_1624022854428_324" n="N001"/><supplied reason="article_added">1</supplied> Von dem Menschen vor dem fall.</head>
            <p facs="#facs_13_TextRegion_1624022900738_331">
               <lb facs="#facs_13_line_1624022854429_325" n="N001"/>Gott hat von anfang den Menschen erschaffen
               <lb facs="#facs_13_r2l4" n="N002"/><note place="margin-left" facs="#facs_13_TextRegion_1624023026742_370">
               some shortened text, so that you are not annoyed by too much scrolling
            </p>
         </div>
         <div><head facs="#facs_13_TextRegion_1624022956839_350">
            <lb facs="#facs_13_line_1624022956945_353" n="N001"/><supplied reason="article_added">2</supplied> Von dem Menschen nach dem fall.</head>
            <p facs="#facs_13_TextRegion_1624022990460_362">
               <lb facs="#facs_13_line_1624022956946_354" n="N001"/>Aber nach dem unser erster vatter wider Gottes
               here the text would continue

</body>
</text>

(the file in question can be downloaded here )

These <div> unfortunately are not the only one relevant, so I decided to group things together by the following script:

<?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" version="3.0">
    <xsl:template match="/">

        <xsl:for-each-group select="*" group-starting-with="div/head">
            <div class="test">
                <xsl:apply-templates select="current-group()"/>
            </div>
        </xsl:for-each-group>
    </xsl:template>

    <xsl:template match="head">
        <xsl:element name="div">
            <xsl:element name="hr"/>
            <xsl:attribute name="class">
                <xsl:text>test;</xsl:text>
            </xsl:attribute>
            <xsl:copy-of select="."></xsl:copy-of>
            <xsl:element name="hr"/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

This, however, simply copies the text inside one big <div class="test"> without any tags etc. so I am quite sure I amk doing something wrong here.

edit: some additions - sorry The ultimate goal is to divide the xml-file into several small ones, that are indicated by the grouping-structure <div><head>...</head>...</div>. These form the sub-chapters of the text and need analysing without splitting the file manually :-D

1 Answers

It is hard to tell without seeing some more context of the input structure but for sure an attempt to match on / and then use <xsl:for-each-group select="*" group-starting-with="div/head"> inside can't do more that process and group the existing root element.

So somehow you will need to move your processing to the right level, hard to tell where exactly without seeing the document structure.

Given the structure you have shown in your edit and the requirement to split into separate files your intent to use group-starting-with could be adapted to e.g.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="#all"
  expand-text="yes">

  <xsl:mode on-no-match="shallow-copy"/>
  
  <xsl:template match="TEI">
    <xsl:for-each-group select="text/body/div" group-starting-with="div[head]">
      <xsl:result-document href="head-doc-{substring(head/@facs, 2)}.xml">
        <xsl:apply-templates select="/" mode="split"/>
      </xsl:result-document>
    </xsl:for-each-group>
  </xsl:template>
  
  <xsl:mode name="split" on-no-match="shallow-copy"/>
  
  <xsl:template mode="split" match="body/*">
    <xsl:if test=". intersect current-group()">
      <xsl:next-match/>
    </xsl:if>
  </xsl:template>
  
</xsl:stylesheet>
Related