Wednesday, July 9, 2008

Xsl function to testing if text only contains footnote marks

The situation come up were I had a table of data and in on of the columns it had just footnote marks. Well I had to merge these footnote marks over to the previous column, but in order to do this I needed to know if the only value in the cell were marks. So I realize there are many ways to do this but I thought this was a cool way. It reads in an external xml file with all the footnote refs I want to search for the ref value is a regex.
<footnotes>
<footnote ref="\*"/>
<footnote ref="\+"/>
<footnote ref="†"/>
<footnote ref="\([a-z]\)"/>
<footnote ref="\([1-9]\)"/>
</footnotes>

I then concat the refs together with a | and do a replace on the string value. If nothing is left then it is a footnote ref.


<!-- Reads all possible footnote ref marks from a footnotes.xml file and if pText only contains footnote marks returns true otherwise false -->
<xsl:function name="txt:IsFootnoteRef" as="xs:boolean">
<xsl:param name="pText" as="xs:string"/>
<xsl:variable name="vFootnotes" select=" document('./footnotes.xml')/footnotes/footnote"/>
<xsl:choose>
<xsl:when test="not($vFootnotes)">
<xsl:value-of select="false()"/>
</xsl:when>
<xsl:when test="not($pText)">
<xsl:value-of select="false()"/>
</xsl:when>
<xsl:when test="normalize-space($pText) = '' ">

<xsl:value-of select="false()"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="vFootnoteRef">
<xsl:value-of select="$vFootnotes/@ref" separator="|"/>
</xsl:variable>

<xsl:choose>
<xsl:when test=" normalize-space(replace($pText, $vFootnoteRef , '' , 'i')) = '' ">
<xsl:value-of select="true()"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="false()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:function>

Labels: , ,

Tuesday, March 4, 2008

Comparing XML attributes with parents attributes

I had a need to test if all/most of the attributes of a child node were equal to its parent and strip out the child node if true.

My XML structure was basically:

<PARAGRAPH style='heading1' emphasis='true' font='arial' number='30' indent=’10’>

<SPECIALTEXT style='heading1' emphasis='true' font='arial' number='31'>

Helloworld

</SPECIALTEXT>

</PARAGRAPH>

Output needed to be:

<PARAGRAPH style='heading1' emphasis='true' font='arial' number='30'>

Helloworld

</PARAGRAPH>

Now this only works on the first level after the PARAGRAPH but that’s all I needed, and it could be changed to do this recursively I guess. Basically I am matching on any paragraph that contains a child element SPECIALTEXT with the same style attribute and calling the template CompareKeyAttributes.
PARAGRAPH has more attributes than SPECIALTEXT in most cases so I compare only the ones that exist in SPECIALTEXT.

CompareKeyAttributes will return a string of all the
attributes that don’t match so then I just check if I care that the attribute
is different and output accordingly.

<xsl:template match="PARAGRAPH[SPECIALTEXT[@Style=./@Style] ] ">

<xsl:copy>

<xsl:apply-templates select="@*"/>

<xsl:for-each select=" child::*">

<xsl:variable name="RESULT">

<xsl:call-template name="CompareKeyAttributes">

<xsl:with-param name="PARA" select=".."/>

<xsl:with-param name="SPEC" select="."/>

</xsl:call-template>

</xsl:variable>

<xsl:choose>

<xsl:whentest="$RESULT='number' ">

<xsl:apply-templates select="child::node()"/>

</xsl:when>

<xsl:otherwise>

<xsl:copy>

<xsl:apply-templates select="@*|node()"/>

</xsl:copy>

</xsl:otherwise>

</xsl:choose>

</xsl:for-each>

</xsl:copy>

</xsl:template>

<xsl:template name="CompareKeyAttributes">

<xsl:param name="PARA"/>

<xsl:param name="SPEC"/>

<xsl:for-each select="$SPEC/@*">

<xsl:variable name="SPEC_ATT" select="name()"/>

<xsl:variable name="PARA_ATT" select="$PARA/@*[name()= $SPEC_ATT]"/>

<xsl:choose>

<xsl:when test="$PARA_ATT != .">

<xsl:value-of select="name()"/>

</xsl:when>

</xsl:choose>

</xsl:for-each>

</xsl:template>

Let me know if you find this useful or have anyway to make it better. Enjoy

Labels: , , ,