Comparing multiple strings in Schematron

Questions about XML that are not covered by the other forums should go here.
shudson310
Posts: 151
Joined: Sat Feb 26, 2005 12:09 am
Location: USA
Contact:

Comparing multiple strings in Schematron

Post by shudson310 » Wed Nov 25, 2020 2:21 am

I've got the following source:

Code: Select all

<dt><xref
                href="https://staging.example.com/example.html"
                format="html" scope="external" product="staging">My link 
                text</xref><xref
                href="https://production.example.com/example.html"
                format="html" scope="external" product="production">My link 
                text</xref><xref
                href="../example.xml"
                format="html" scope="external" product="local">Different link 
                text</xref></dt>
I need to create a Schematron to compare these values and report any different links.

I've got:

Code: Select all

<sch:pattern>
        <sch:rule context="*[count(xref = 3)]">
            <sch:let name="stag"><xsl:value-of select="normalize-space(xs:string(xref[@product='staging]))"/></sch:let>
            <sch:let name="prod"><xsl:value-of select="normalize-space(xs:string(xref[@product='production']))"/></sch:let>
            <sch:let name="local"><xsl:value-of select="normalize-space(xs:string(xref[@product='local']))"/></sch:let>
            <sch:assert id="myRule"
                test="($stag = $prod) and ($stag = $local)"
                role="error"
                sqf:fix="addPeriod">myRule: The text of this group of links must all match.</sch:assert>
        </sch:rule>
    </sch:pattern>
But I'm getting an error:
Engine name: ISO Schematron
Severity: warning
Description: Cannot convert string "My link\n..." to double
Start location: 889:41
As you can see, I tried to normalize spaces and ensure that they are strings.

Any ideas how to properly compare these strings in Schematron?
Scott Hudson
Staff Content Engineer
Site: docs.servicenow.com

shudson310
Posts: 151
Joined: Sat Feb 26, 2005 12:09 am
Location: USA
Contact:

Re: Comparing multiple strings in Schematron

Post by shudson310 » Wed Nov 25, 2020 5:43 am

OK, I have it closer, but now it is triggering on all of the links?

Code: Select all

<sch:pattern>
        <sch:rule context="*[count(xref = 3)]">
            <sch:let name="stag"><xsl:value-of select="normalize-space(xs:string(xref[@product='staging]))"/></sch:let>
            <sch:let name="prod"><xsl:value-of select="normalize-space(xs:string(xref[@product='production']))"/></sch:let>
            <sch:let name="local"><xsl:value-of select="normalize-space(xs:string(xref[@product='local']))"/></sch:let>
            <sch:assert id="myRule"
                test="('$stag' = '$prod') and ('$stag' = '$local')"
                role="error"
                sqf:fix="addPeriod">myRule: The text of this group of links must all match.</sch:assert>
        </sch:rule>
    </sch:pattern>
I only want to flag when the values are NOT equal.
Scott Hudson
Staff Content Engineer
Site: docs.servicenow.com

tavy
Posts: 291
Joined: Thu Jul 01, 2004 12:29 pm

Re: Comparing multiple strings in Schematron

Post by tavy » Wed Nov 25, 2020 11:09 am

Hello,
The context must be "*[count(xref) = 3]", and the variables must be without quotes.
I think the pattern should be something like this:

Code: Select all

<sch:pattern>
    <sch:rule context="*[count(xref) = 3]">
        <sch:let name="stag" value="normalize-space(xs:string(xref[@product='staging']))"/>
        <sch:let name="prod" value="normalize-space(xs:string(xref[@product='production']))"/>
        <sch:let name="local" value="normalize-space(xs:string(xref[@product='local']))"/>
        <sch:assert id="myRule"
            test="($stag = $prod) and ($stag = $local)"
            role="error">myRule: The text of this group of links must all match.</sch:assert>
    </sch:rule>
</sch:pattern>
Best Regards,
Octavian
Octavian Nadolu
<oXygen/> XML Editor
http://www.oxygenxml.com

shudson310
Posts: 151
Joined: Sat Feb 26, 2005 12:09 am
Location: USA
Contact:

Re: Comparing multiple strings in Schematron

Post by shudson310 » Mon Nov 30, 2020 9:42 pm

I was close, but just not getting it quite right.

That did it. Thanks, so much, Octavian!
Scott Hudson
Staff Content Engineer
Site: docs.servicenow.com

shudson310
Posts: 151
Joined: Sat Feb 26, 2005 12:09 am
Location: USA
Contact:

Re: Comparing multiple strings in Schematron

Post by shudson310 » Tue Dec 01, 2020 12:10 am

Certain topics are now returning a fatal Schematron error:
A sequence of more than one item is not allowed as the value in 'cast as' expression (<xref>, <xref>)
My guess is that not all of these contain text to compare? I've tried adding:

Code: Select all

<sch:let name="empty"/>
            <sch:assert id="now014"
                test="($stag != $empty) and ($prod != $empty) and ($local != $empty) and ($stag = $prod) and ($stag = $local)"
                role="error">
but am still getting the error.
Scott Hudson
Staff Content Engineer
Site: docs.servicenow.com

tavy
Posts: 291
Joined: Thu Jul 01, 2004 12:29 pm

Re: Comparing multiple strings in Schematron

Post by tavy » Thu Dec 03, 2020 6:10 pm

Hello,

I don't know exactly what rule you want to add, and what is the structure you want to impose.
Probably this error occurs because you have two xref elements with the same value in the @product attribute.
I think first you need to check if all the xref elements are correct. You can check if you have a "staging", a "production, and a "local". The you can check also the text. Something like this:

Code: Select all

<sch:pattern>
    <sch:rule context="*[count(xref) = 3]">
        <sch:let name="staging" value="xref[@product='staging']"/>
        <sch:let name="production" value="xref[@product='production']"/>
        <sch:let name="local" value="xref[@product='local']"/>
        
        <sch:let name="stagingNo" value="count($staging)"/>
        <sch:let name="productionNo" value="count($production)"/>
        <sch:let name="localNo" value="count($local)"/>
        <sch:assert test="$stagingNo = 1">One staging xref is expected, are <sch:value-of select="$stagingNo"/></sch:assert>
        <sch:assert test="$productionNo = 1">One production xref is expected, are <sch:value-of select="$productionNo"/></sch:assert>
        <sch:assert test="$localNo = 1">One local xref is expected, are <sch:value-of select="$localNo"/></sch:assert>
      
        <sch:assert id="myRule"
            test="$stagingNo = 1 and $productionNo = 1 and $localNo = 1 and
            (normalize-space($staging) = normalize-space($production)) and (normalize-space($staging) = normalize-space($local))"
            role="error">myRule: The text of this group of links must all match.</sch:assert>
    </sch:rule>
</sch:pattern>
Best Regards,
Octavian
Octavian Nadolu
<oXygen/> XML Editor
http://www.oxygenxml.com

Post Reply