Reputation: 533
I have a series of P tags in XML content that have a semantic hierarchy within their beginning values, however, the P tags are linear. Looking for the XSLT 2 transformation.
Semantic hierarchy is as follows:
(1)
+-(a)
+-(I)
+-(A)
With RegEx sequence as follows:
<xsl:param name="patternOrder" as="element(pattern)*" xmlns="">
<pattern level="1" value="^(\([0-9]+(\.[0-9]+)?\))" />
<pattern level="2" value="^(\([a-z]\))" />
<pattern level="3" value="^(\((IX|IV|V?I{{0,3}})\))" />
<pattern level="4" value="^(\([\w]+(\.[\w]+)?\))" />
</xsl>
After review of my dataset, I have the various conditions:
<?xml version="1.0" encoding="UTF-8"?>
<test>
<content>
<p>(1) blah</p>
<p>(2)(a) blah</p>
<p>(b) blah</p>
<p>(3)(a)(I) blah</p>
<p>(II) blah</p>
<p>(A) blah</p>
<p>(B.1) blah</p>
<p>(b) blah</p>
<p>(4) blah</p>
<p>(4.5) blah</p>
<p>(5)(a)(I)(A) blah</p>
<p>(B) blah</p>
<p>(II) blah</p>
<p>(III)(a) blah</p>
<p>(bb.2) blah</p>
<p>(6) blah</p>
</content>
<content>
<p>blah</p>
</content>
<content>
<p>blah</p>
<p>(1) blah</p>
<p>(a) blah</p>
<p>(b) blah</p>
<p>(2) blah </p>
</content>
</test>
...and end results should be:
<?xml version="1.0" encoding="UTF-8"?>
<test>
<content>
<p>(1) blah</p>
<p>(2)
<p>(a) blah</p>
<p>(b) blah</p>
</p>
<p>(3)
<p>(a)
<p>(I) blah</p>
<p>(II) blah
<p>(A) blah</p>
<p>(B) blah</p>
</p>
</p>
<p>(b) blah</p>
</p>
<p>(4) blah</p>
<p>(4.5) blah</p>
<p>(5)
<p>(a)
<p>(I)
<p>(A) blah</p>
<p>(B.1) blah</p>
</p>
<p>(II) blah</p>
<p>(III)</p>
<p>(a) blah</p>
<p>(bb.2) blah</p>
</p>
</p>
<p>(6) blah</p>
</content>
<content>
blah
</content>
<content>
blah
<p>(1) blah
<p>(a) blah</p>
<p>(b) blah</p>
</p>
<p>(2) blah </p>
</content>
</test>
Please note the condition if the semantic hierarchy is not present in the P tag - then the P tag is removed and is a value of its parent content element.
I have been able to detect all the semantic conditions using the following RegEx:
^(\(([\w]+(\.[\w]+)?)\)){1,4}
With the leveling attributes:
<?xml version="1.0" encoding="UTF-8"?>
<test>
<content>
<p level="1">(1) blah</p>
<p level="1">(2)</p>
<p level="2">(a) blah</p>
<p level="2">(b) blah</p>
<p level="1">(3)</p>
<p level="2">(a)</p>
<p level="3">(I) blah</p>
<p level="3">(II) blah</p>
<p level="4">(A) blah</p>
<p level="4">(B.1) blah</p>
<p level="2">(b) blah</p>
<p level="1">(4) blah</p>
<p level="1">(4.5) blah</p>
<p level="1">(5)</p>
<p level="2">(a)</p>
<p level="3">(I)</p>
<p level="4">(A) blah</p>
<p level="4">(B) blah</p>
<p level="3">(II) blah</p>
<p level="3">(III)</p>
<p level="2">(a) blah</p>
<p level="2">(bb.2) blah</p>
<p level="2">(6) blah</p>
</content>
<content>
<p>blah</p>
</content>
<content>
<p>blah</p>
<p level="1">(1) blah</p>
<p level="2">(a) blah</p>
<p level="2">(b) blah</p>
<p level="1">(2) blah </p>
</content>
</test>
Upvotes: 3
Views: 135
Reputation: 163458
First phase: transform
<p>(2)(a) blah</p>
<p>(b) blah</p>
into
<p>(2)</p>
<p>(a) blah</p>
<p>(b) blah</p>
using something like
<xsl:template match="p">
<xsl:for-each select="tokenize(., '\(')">
<xsl:if test="normalize-space(.)">
<p>(<xsl:value-of select="."/></p>
</xsl:if>
</xsl:for-each>
</xsl:template>
Second phase:
First write a function
<xsl:function name="f:level" as="xs:integer">
<xsl:param name="p" as="element(p)"/>
....
</xsl:function>
which computes the "semantic level" based on matching your regular expressions. You seem to know how to do this part.
Then write a recursive grouping function:
<xsl:function name="f:group" as="element(p )*">
<xsl:param name="in" as="element(p )*"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:for-each-group select="$in" group-starting-with="p[f:level(.)=$level]">
<p><xsl:value-of select="current-group()[1]"/>
<xsl:sequence select="f:group(current-group()[position() gt 1], $level+1)"/>
</p>
</xsl:for-each-group>
</xsl:function>
and call this function like this:
<xsl:template match="content">
<xsl:sequence select="f:group(p, 1)"/>
</xsl:template>
Not tested.
Upvotes: 2