Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XSLT template for any node not already handled?

Is it possible to match 'Any node not already matched/handled'? Preferably without making my style sheet into an enormous for-each/Choose statement, as the current ordering is critical.

The project is still in development and already being used in the live environment, so the code is, simply put, in a state of rapid flux in response to live data we're getting in. I am generating a PDF document via FO from XML that may have nodes in it that I don't know about yet, and would like to add a "fail over" instruction to my XSL-FO transform that puts all the unaccounted-for nodes at the beginning of the document in bright red, to speed up discovery.

I can't just ignore surprise nodes, as the data needs to be handled. The quicker I can find "orphan" data, the quicker I can get it properly handled and out the door.

I have tried playing around with <xsl:template match="*">...</xsl:template> and various priority="" settings, but of course it applies to every node.

For example, I might have this in one section because these XML blocks are not guarenteed to come in the correct output order. (Code block formatting is not working for me - four space indent results in nothing, sorry :(

<xsl:template match="AccountSummary">
    <fo:block margin-left="2" space-before="1" space-after="1" text-align="center">
        <xsl:apply-templates select="Label"/>
    </fo:block>
    <xsl:apply-templates select="AccountInfo"/>
    <xsl:apply-templates select="AccountProfile"/>
    <xsl:apply-templates select="ChangeInValueOfAccounts"/>
    <!-- ... more goes here -->
</xsl:template>

I would like to do something like

<xsl:template match="AccountSummary">
    <fo:block margin-left="2" space-before="1" space-after="1" text-align="center">
        <xsl:apply-templates select="Label"/>
    </fo:block>
    <xsl:apply-templates select="AccountInfo"/>
    <xsl:apply-templates select="AccountProfile"/>
    <xsl:apply-templates select="ChangeInValueOfAccounts"/>
    <!-- ... more goes here -->
    <xsl:for-each select="not otherwise matched">
        <!-- call zomgRED template -->
    </xsl:for-each>
</xsl:template>

Ideally I'd rather the zomgREDs to be at the top, but at the bottom will work too. Or flagged with text markers. Anything to spit out the text in the final document instead of silently eating it.

like image 926
BrunoXSLT Avatar asked Nov 04 '22 00:11

BrunoXSLT


1 Answers

Here's how you might be able to get some flavor of what you are looking for. Though no pushing the unprocessed nodes up to the top:

1) have the identity transformation in your stylesheet:

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

2) make sure you call <xsl:apply-templates select="*"/> from all other more specific templates to let the parser going

The idea is that your specific templates handle the intended transformation to XSL-FO while the identity transform just dumps out everything else into the result tree. The recursive calls will ensure you actually touch all nodes (this is the only way to get them "on record") and the identity transformation will match those you didn't catch otherwise.

That #2 advise can actually get in a way of your XSL-FO logic so may not really be feasible, I can't tell without having an example input and your current XSL-FO transform. Maybe add it to the question?

like image 113
Pavel Veller Avatar answered Nov 15 '22 06:11

Pavel Veller