Schematron sqf:stringReplace case-insensitive

Here should go questions about transforming XML with XSLT and FOP.
proxx
Posts: 6
Joined: Wed Dec 16, 2015 3:49 pm

Schematron sqf:stringReplace case-insensitive

Post 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?
xephon
Posts: 136
Joined: Mon Nov 24, 2014 1:49 pm
Location: Greven/Germany

Re: Schematron sqf:stringReplace case-insensitive

Post 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
stefan-jung.org – Your DITA/DITA-OT XML consultant
proxx
Posts: 6
Joined: Wed Dec 16, 2015 3:49 pm

Re: Schematron sqf:stringReplace case-insensitive

Post 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.
tavy
Posts: 364
Joined: Thu Jul 01, 2004 12:29 pm

Re: Schematron sqf:stringReplace case-insensitive

Post 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
Octavian Nadolu
<oXygen/> XML Editor
http://www.oxygenxml.com
proxx
Posts: 6
Joined: Wed Dec 16, 2015 3:49 pm

Re: Schematron sqf:stringReplace case-insensitive

Post by proxx »

Hello Octavian,

Thank you! Your workaround works good.

Take care,
Wojtek
tavy
Posts: 364
Joined: Thu Jul 01, 2004 12:29 pm

Re: Schematron sqf:stringReplace case-insensitive

Post 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)(?<=^|\W)(',$phrase,')(?=\W|$)')}">
....
</sqf:stringReplace>
Read more about the "sqf:stringReplace" in our user manual:
https://www.oxygenxml.com/doc/versions/ ... tions.html

Best Regards,
Octavian
Octavian Nadolu
<oXygen/> XML Editor
http://www.oxygenxml.com
Post Reply