Search code examples
stringxsltxpathcdata

Matching strings inside <![CDATA]>


I have a DMN document that is using <![CDATA["text"]]> to represent string values. I am trying to all the words in an input string against one of the strings in these CDATA sections but I cannot figure out which XPath expression will do the trick.

Here is a sample DMN file:

<definitions xmlns="http://www.omg.org/spec/DMN/20151101/dmn.xsd" id="definitions_0fyde0d"
name="definitions" namespace="http://camunda.org/schema/1.0/dmn">
<decision id="decision" name="TroubleArea">
    <decisionTable id="decisionTable">
        <input id="input1" label="UserText">
            <inputExpression id="inputExpression1" typeRef="string">
                <text/>
            </inputExpression>
        </input>
        <output id="output1" label="Subsystem" name="" typeRef="string"/>
        <rule id="row-22012340-2">
            <inputEntry id="UnaryTests_1hacpom">
                <text><![CDATA["signal", "input", "connection"]]></text>
            </inputEntry>
            <outputEntry id="LiteralExpression_0wvuvyc">
                <text><![CDATA["input"]]></text>
            </outputEntry>
        </rule>
        <rule id="row-22012340-3">
            <inputEntry id="UnaryTests_0cmpu76">
                <text><![CDATA["screen"]]></text>
            </inputEntry>
            <outputEntry id="LiteralExpression_0hkc81e">
                <text><![CDATA["output"]]></text>
            </outputEntry>
        </rule>
    </decisionTable>
</decision>

The input is a single string, which needs to be matched against any string between quotes in the CDATA sections of <inputEntry> elements. When the match is found, I need to return the string in the <outputEntry> of the same <rule>.

After adding the namespace into my XSL, I can match the <decisionTable>, but I am still not getting any matches on any of the strings. Here is the code I am using to check if there are matches at all. This is not getting the <outputEntry> string yet, just "Yes" or "No" to tell me if there is a match at all.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:dmn="http://www.omg.org/spec/DMN/20151101/dmn.xsd"
exclude-result-prefixes="xs"
version="2.0">

<xsl:output method="xml" encoding="UTF-8"/>

<xsl:param name="input"/>

<xsl:template match="/">
    <result>
        <xsl:variable name="table">
            <xsl:value-of select="//dmn:decisionTable"/>
        </xsl:variable>
        <xsl:for-each select="distinct-values(tokenize($input,'%20'))">
            <item>
                <xsl:value-of select="."/>
                <xsl:text>: </xsl:text>
                <xsl:call-template name="matchrule">
                    <xsl:with-param name="text">
                        <xsl:value-of select="concat('&quot;',.,'&quot;')"/>
                    </xsl:with-param>
                    <xsl:with-param name="table">
                        <xsl:value-of select="$table"/>
                    </xsl:with-param>
                </xsl:call-template>
            </item>
        </xsl:for-each>     
    </result>
</xsl:template>

<xsl:template name="matchrule">
    <xsl:param name="table"/>
    <xsl:param name="text"/>
        <xsl:choose>
            <xsl:when test="$table//dmn:rule[contains(dmn:inputEntry/dmn:text,$text)]">
                <xsl:text>Yes</xsl:text>
            </xsl:when>
            <xsl:otherwise>
                <xsl:text>No</xsl:text>
            </xsl:otherwise>
        </xsl:choose>
</xsl:template>

Testing this with the input string "something%20with%20the%20screen%20or%20the%20screen%20brightness" gives the result:

result xmlns:dmn="http://www.omg.org/spec/DMN/20151101/dmn.xsd">
<item>something: No</item>
<item>with: No</item>
<item>the: No</item>
<item>screen: No</item>
<item>or: No</item>
<item>brightness: No</item>

I cannot change the DMN to not use those <![CDATA]> entries, as the table is created by another tool that I have no control over.


Solution

  • I think one way is to use

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xpath-default-namespace="http://www.omg.org/spec/DMN/20151101/dmn.xsd"
    exclude-result-prefixes="xs"
    version="2.0">
    
    <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
    
    <xsl:param name="input">something%20with%20the%20screen%20or%20the%20screen%20brightness</xsl:param>
    
    <xsl:template match="/">
        <result>
            <xsl:variable name="rules" select="//rule"/>
    
            <xsl:for-each select="distinct-values(tokenize($input,'%20'))">
                <item>
                    <xsl:value-of select="."/>
                    <xsl:text>: </xsl:text>
                    <xsl:apply-templates select="$rules[inputEntry/text[contains(., concat('&quot;', current(), '&quot;'))]]"/>
                </item>
            </xsl:for-each>     
        </result>
    </xsl:template>
    
    <xsl:template match="rule">
        <xsl:value-of select="outputEntry/text"/>
    </xsl:template>
    
    </xsl:stylesheet>
    

    which outputs

    <result>
       <item>something: </item>
       <item>with: </item>
       <item>the: </item>
       <item>screen: "output"</item>
       <item>or: </item>
       <item>brightness: </item>
    </result>
    

    Online sample http://xsltransform.net/gVhD8RW.