Is it possible to replace/substitute the incoming XSL data?

I tried to look for an answer on google, but the results i get back is either how to substitute a string or replacing a substring etc. But my question is slightly different.

Say I have an existing XSL template, say "hello-world", that processes "data/records/record", but I cannot modify hello-world, so I'm thinking of creating a wrapper template that will massage/modify the data inside each record before passing it to hello-world... is there a way to do that?

So far, I've managed to create a function that would filter out the duplicate records, and I was thinking of replacing all the records inside "data/records/*" with the new one...

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">


    <xsl:template match="/">
        <xsl:call-template name="get-unique-record">
            <xsl:with-param name="records" select="/data/records/record"/>
        </xsl:call-template>
    </xsl:template>

    <!-- This function will filter out the given records and return a unique set of records -->
    <xsl:key name="kField_ID" match="field[@name='ID']" use="."/>
    <xsl:template name="get-unique-record">
        <xsl:param name="records"/>
        <xsl:for-each select="$records">
            <xsl:variable name="record" select="."/>
            <xsl:if test="$record//field[generate-id() = generate-id(key('kField_ID', .))]">
            <xsl:copy-of select="$record"/>         
            </xsl:if>
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

Now... is it possible to do something like:

<xsl:variable name="/data/records/record">
    <xsl:call-template name="get-unique-record">
        <xsl:with-param name="records" select="/data/records/record"/>
    </xsl:call-template>
</xsl:variable>

EDIT: @LasrH, thanks for the quick reply. Is there a way to make a copy of the existing "/" and then replace all the /data/records/record with the filtered one?

EDIT2: @LasrH, I created couple of template to modify and rebuild the "data" node. Is it possible to use node-set to "replace" the existing input with my new data as input?

<xsl:variable name="data">
    <xsl:call-template name="rebuild-data-with-record">
        <xsl:with-param name="records">
                    <xsl:copy-of select="$unique-records"></xsl:copy-of>
                    </xsl:with-param>
    </xsl:call-template>
</xsl:variable>

Then further down I tried to use node-set like this:

<xsl:apply-templates select="exslt:node-set($data)/data"/>

But it doesn't look like is doing it... there is no error thrown either.

Answers


No, in XSL you cannot modify the source document in-place.

However, you can massage the source document upstream (using a separate XSL stylesheet), and pass the massaged document to the XSL stylesheet that calls "hello-world" template, instead of letting it process the original source document.

You can even do this within the same stylesheet that contains "hello-world", if you are able to modify that stylesheet. (But I guess you can't modify that stylesheet, or you would be able to modify "hello-world".)


Actually, after much research and trials, you CAN "replace/substitute" data at the XSL level!!! You just need to rebuild the root node yourself, and pass your "modified root" (RTF cast it back into node-set) to your template and have your template read it off your own data instead!!!

I asked another question here, which was part of my experiment to get this to work: Unable to cast from XRTreeFrag into XNodeSet

The idea is this, you have a template function that read/deal with the incoming data, and we pretty much always read the input off the root /blah/blah/blah... Rather than reading it off the root, you can do this in EVERY/ANY of your template:

<xsl:template name="helloworld">
    <xsl:param name="inputRoot" select="/"/>
    <xsl:variable name="root" select="$inputRoot"/>
    rest of your code goes here...

Now, replace all your root access with $root/blah/blah/blah and it will take in your modified XSL data!

Cool thing about this is that, if you don't pass any input data, it will just assume the input to be root! ;)

This was tested and work flawlessly. There is only one concern I have however, if the XSL input is HUGE, reconstructing the whole root might cause performance issue. But my input was only two dozen records, and there were zero performance hit for my case.

So you may want to double check if your input data is large.

This solution/method is XSL 1.0 friendly.


Need Your Help

Django performance - The mysterious 11 seconds

django performance

I am having some performance problems that have left me baffled. I am using Django with MySQL. I do the following:

Convert Javascript object to JSON just one time in Angularjs

javascript angularjs json

I want to convert javascript object to JSON with angular.toJson just one time.