Reputation: 527
I have an XSLT implementation that hyphenates strings following latex patterns, i.e. inserts soft hyphens in strings. I call this function like this:
<xsl:template match="p[lang('en')]/text()">
<xsl:analyze-string select="." regex="\w+">
<xsl:matching-substring>
<xsl:value-of select="fn:hyphenate(., '', 'en')"/>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
Now, before I call the hyphenate
function, I would like to consult a list of exceptions. I'm fairly flexible about the format in which I get the exceptions, but I would also like to use this opportunity to learn how to take advantage of json objects from within XSLT 3.0.
So let's say i have a JSON file called exceptions.json
that looks like this:
{
"en" :{
"recognizance": "re-cog-ni-zance",
"reformation": "ref-or-ma-tion",
"retribution": "ret-ri-bu-tion",
"table": "ta-ble"
},
"de" : {
//etc.
}
}
(I am not using soft hyphens in the above example because they wouldn't show on Stackoverflow, but that's irrelevant for the question I am asking).
How could I read (and parse?) the contents of the JSON file into a variable called $exceptions
, so that I could most efficiently do something like:
<xsl:template match="p[lang('en')]/text()">
<xsl:analyze-string select="." regex="\w+">
<xsl:matching-substring>
<xsl:choose>
<xsl:when test="">
<!--test if matched string is a key in my json object and return the
corresponding value. for instance, if the matched substring here is
"table", I'd like to return something like
<xsl:value-of select="$exceptions['en']['table']"/> ,
i.e. "ta-ble", using whatever notation may be correct for this
kind of thing. -->
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="fn:hyphenate(., '', 'en')"/>
</xsl:otherwise>
</xsl:choose>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
Many thanks in advance!
Upvotes: 0
Views: 170
Reputation: 117140
Another option is to convert the JSON to XML, then process it as such.
In your example, this could probably look something like:
XSLT 3.0
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:your="your-namespace-here"
exclude-result-prefixes="#all">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="exceptions" select="json-to-xml(unparsed-text('path/to/exceptions.json'))" />
<xsl:key name="excpt" match="fn:string" use="@key" />
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="p">
<xsl:analyze-string select="." regex="\w+">
<xsl:matching-substring>
<xsl:variable name="lookup" select="key('excpt', ., $exceptions)" />
<xsl:value-of select="if($lookup) then $lookup else your:hyphenate(.)" />
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>
Untested, because you did not provide a reproducible example. Do note that I am using the fn
prefix as intended by the W3C Recommendation; you will need to use another prefix for your own function.
Upvotes: 0
Reputation: 167716
Well, the XPath 3.1 and the XSLT 3.0 specs are online, so you could have found the necessary functions (https://www.w3.org/TR/xpath-functions-31/#func-json-doc, https://www.w3.org/TR/xpath-functions-31/#func-map-contains) and notations (https://www.w3.org/TR/xpath-31/#id-lookup).
Use e.g. <xsl:variable name="exceptions" select="json-doc('exceptions.json')"/>
, the you can access e.g. map:contains($exceptions?en, .)
to check whether the current word is in the en
map.
Example: (reading JSON inline for self-containedness):
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:output method="html" indent="yes" html-version="5"/>
<xsl:template match="p[lang('en')]/text()">
<xsl:analyze-string select="." regex="\w+">
<xsl:matching-substring>
<xsl:choose>
<xsl:when test="map:contains($exceptions?en, .)">
<xsl:sequence select="$exceptions?en(.)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="/" name="xsl:initial-template">
<xsl:copy>
<xsl:apply-templates/>
<xsl:comment>Run with {system-property('xsl:product-name')} {system-property('xsl:product-version')} at {current-dateTime()}</xsl:comment>
</xsl:copy>
</xsl:template>
<xsl:param name="json-exceptions" as="xs:string" expand-text="no">
{
"en" :{
"recognizance": "re-cog-ni-zance",
"reformation": "ref-or-ma-tion",
"retribution": "ret-ri-bu-tion",
"table": "ta-ble"
}
}
</xsl:param>
<xsl:param name="exceptions" select="parse-json($json-exceptions)"/>
</xsl:stylesheet>
Upvotes: 1