Page 1 of 1

Schematron sqf:stringReplace case-insensitive

Posted: Fri Jul 08, 2016 4:08 pm
by proxx
Hello,

I have created a schematron rule that searches for a particular text given by a variable in a case-insensitive manner (provided by "i" flag):

Code: Select all

<sch:report test="matches(.,concat('(^|\W)',$phrase,'(\W|$)'),'i')" role="error" sqf:fix="replaceWithKey">...</sch:report>

where $phrase = '(phrase)'

I want a user to be able to use a quick fix and replace the text, but I don't know how to provide a case-insensitive solution in the quick fix. My initial version looks like this:

Code: Select all

<sqf:fix id="replaceWithKey">
<sqf:stringReplace regex="{$phrase}">
...
</sqf:stringReplace>

the quick fix works only if the part of the text has exactly the same capitalization as $phrase, though the rule violation is recognized in every case. Is there a way to utilize the "i" flag functionality in the regex attribute?

Re: Schematron sqf:stringReplace case-insensitive

Posted: Fri Jul 08, 2016 10:09 pm
by xephon
Hi proxx,

this is a different approach, but maybe it helps you solving your problem:

Code: Select all

<sch:pattern id="term">
    <sch:rule context="text()">
        <sch:let name="capitalizedDeprecatedTerm" value="concat(upper-case(substring('foo', 1, 1)), substring('foo', 2), ' '[not(last())])"/>
        <sch:let name="capitalizedRecommendedTerm" value="concat(upper-case(substring('bar', 1, 1)), substring('bar', 2), ' '[not(last())])"/>
        <sch:report test="contains(., 'foo')"
            role="warning"
            sqf:fix="sqfReplaceTerm">The term 'foo' is not allowed, use 'bar'.</sch:report>
        <sqf:fix id="sqfReplaceTerm">
            <sqf:description>
                <sqf:title>Replace with an allowed term: 'bar'</sqf:title>
                <sqf:p>A bar is a retail business establishment that serves alcoholic beverages.</sqf:p>
            </sqf:description>
            <sqf:stringReplace regex="foo">bar</sqf:stringReplace>
        </sqf:fix>

        <sch:report test="contains(., $capitalizedDeprecatedTerm)"
            role="warning"
            sqf:fix="sqfReplaceCapitalizedTerm">The term '<sch:value-of select="$capitalizedDeprecatedTerm"/>' is not allowed, use '<sch:value-of select="$capitalizedRecommendedTerm"/>'.</sch:report>           
        <sqf:fix id="sqfReplaceCapitalizedTerm">
            <sqf:description>
                <sqf:title>Replace with an allowed term: '<sch:value-of select="$capitalizedRecommendedTerm"/>'</sqf:title>
                <sqf:p>$definition</sqf:p>
            </sqf:description>
            <sqf:stringReplace regex="{$capitalizedDeprecatedTerm}"><sch:value-of select="$capitalizedRecommendedTerm"/></sqf:stringReplace>
        </sqf:fix>
    </sch:rule>
</sch:pattern>


I do not know exactly what you're trying to achieve, but if you want to hack a terminology checker (and use DITA), please try our terminology plugin org.doctales.terminology.

Greetings,
Stefan

Re: Schematron sqf:stringReplace case-insensitive

Posted: Mon Jul 11, 2016 2:05 pm
by proxx
Hi xephon,

Thank you for the reply.

You are right that I am looking for a sort of terminology checker. I have an XSL script that builds a schematron term checker based on multiple (around 300) glossentry topics kept in separate files. The main purpose of the schematron is to inform the user to use a particular key to the glossentry instead of writing pure text. For some terms it concerns both full and abbreviated forms.

Your solution is interesting, but it doesn't give me all the functionality I want to have. For example, I want schematron to recognise places were user wrote "extensible markup language", "eXtensible Markup Language" or "Extensible markup language", but also "xml", "XML", or "Xml". This can be done by

Code: Select all

<sch:report test="matches(.,concat('(^|\W)',$phrase,'(\W|$)'),'i')"...>...<sch:report/>

where

Code: Select all

$phrase='(Extensible\s+Markup\s+Language|XML)'

but the SQF stringReplace function:

Code: Select all

<sqf:stringReplace regex="{$phrase}" >...<sqf:stringReplace/>

will replace only "Extensible Markup Language" or "XML". For other cases it takes no action.

I like the idea of your terminology plugin, I will have a look into that.

Re: Schematron sqf:stringReplace case-insensitive

Posted: Mon Jul 11, 2016 3:25 pm
by tavy
Hello,

You cannot pass the ignore case flag in the stringReplace operation. I will add an issue on the SQF specification to add this support.

As an workaround you can use the "sqf:replace" operation instead and the "xsl:analyze-string" instruction. Something like this:

Code: Select all

<sqf:replace>
    <xsl:analyze-string select="." regex="{$phrase}" flags="i">
        <xsl:matching-substring>...</xsl:matching-substring>
        <xsl:non-matching-substring><xsl:value-of select="."/></xsl:non-matching-substring>
    </xsl:analyze-string>
</sqf:replace>


Best Regards,
Octavian

Re: Schematron sqf:stringReplace case-insensitive

Posted: Wed Jul 13, 2016 7:50 pm
by proxx
Hello Octavian,

Thank you! Your workaround works good.

Take care,
Wojtek

Re: Schematron sqf:stringReplace case-insensitive

Posted: Thu Apr 20, 2017 3:13 pm
by tavy
Hi Wojtek,

Stating with oXygen v18.1 we changed the "sqf:stringReplace" operation to allow using java regular expressions in the value of the @regex attribute.
Therefore, the case-insensitive matching can be enabled via the embedded expression (?i).
In your case you can create a quick fix that uses the "sqf:stringReplace" operation which is faster than the "sqf:replace" operation with an "xsl:analyze-string" instruction. You can create a quick fix operation something like this:

Code: Select all

<sqf:stringReplace regex="{concat('(?i)(?&lt;=^|\W)(',$phrase,')(?=\W|$)')}">
   ....
</sqf:stringReplace>


Read more about the "sqf:stringReplace" in our user manual:
https://www.oxygenxml.com/doc/versions/19.0/ug-editor/topics/sqf-operations.html

Best Regards,
Octavian