Search code examples
xsltnode-set

Returning only nodes by constraint


I have a legacy wddx file (and may have to do this often) that I want to write some XSL for that will get me a count of the number of "top-level" nodes that have a child node with a certain attribute that in turn has a child node with a text value starting with a certain substring. This syntax, for example, gets me a count of 82 nodes (not parents technically, but each parent will have only one "var" node with a name attribute of "task")...

//wddxPacket/data/array/struct/var/struct/var[@name='task']/string/starts-with(text(),"ST_")

... however, the actual # of nodes I'm seeking are all the nodes that are returning true to the condition above...so a count() of that syntax above results in 82...it should be 6 because only six of those results are true.

I think this has to do with node-sets and creating one that revolves around only the condition I am seeking. I don't consider myself a complete noob at XSL...heh...but some of you might. Anyway..I've been searching around and I'm just not sure I'm looking for the right thing and could use some guidance.

Here is an exerpt of the XML (wddx)...

<wddxPacket version="1.0">
<header/>
<data>
    <array length="1">
        <struct type="mydata">
            <var name="serverscheduletask#$%^DEFAULT#$%^SA-QW_71">
                <struct type="schedule-data">
                    <var name="task">
                        <string>SA-QW_71</string>
                    </var>
                </struct>
            </var>
            <var name="serverscheduletask#$%^DEFAULT#$%^ST_FRED">
                <struct type="schedule-data">
                    <var name="task">
                        <string>ST_FRED</string>
                    </var>
                </struct>
            </var>
            <var name="serverscheduletask#$%^DEFAULT#$%^SA-QW_16">
                <struct type="schedule-data">
                    <var name="task">
                        <string>SA-QW_16</string>
                    </var>
                </struct>
            </var>
            <var name="serverscheduletask#$%^DEFAULT#$%^ST_TEST">
                <struct type="schedule-data">
                    <var name="task">
                        <string>ST_TEST</string>
                    </var>
                </struct>
            </var>
            <var name="serverscheduletask#$%^DEFAULT#$%^SA-QW_71">
                <struct type="coldfusion.scheduling.ScheduleTagData">
                    <var name="task">
                        <string>SA-QW_71</string>
                    </var>
                </struct>
            </var>
        </struct>
    </array>
</data>
</wddxPacket>

Solution

  • The xpath expression you have is actually only valid in Xpath 2.0. The starts-with function returns a boolean, so your expression is returning a sequence of booleans.

    false true false true false
    

    If you then use the count function, it will just count up all the boolean values in the sequence, whether they are true or false.

    The expression you probably want is this...

    //wddxPacket/data/array/struct/var/struct/var[@name='task']/string[starts-with(text(),'ST_')]
    

    Or in a count (which returns 1 for your sample XML)

    count(//wddxPacket/data/array/struct/var/struct/var[@name='task']/string[starts-with(text(),'ST_')])