Subject: Re: [xsl] shuffling words in text content From: "Michael Kay mike@xxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> Date: Tue, 7 Sep 2021 19:39:31 -0000 |
Or here's a tested version: random-number-generator()?permute(tokenize('The cat sat on the mat')) => string-join(' ') outputs mat The on the sat cat Michael Kay Saxonica > On 7 Sep 2021, at 20:31, Michael Kay <mike@xxxxxxxxxxxx> wrote: > > What's wrong with > > tokenize(.) => random-number-generator()?permute() => string-join(" ") > > Michael Kay > Saxonica > >> On 7 Sep 2021, at 20:20, Chris Papademetrious christopher.papademetrious@xxxxxxxxxxxx <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote: >> >> Hi everyone, >> >> I recently needed to write a transformation to shuffle words in text content, but still keep the overall element structure intact. For example, I might want to transform >> >> <p>Hey, here is some text!</p> >> >> into >> >> <p>is, text Hey some here!</p> >> >> I didn't see anything exactly like this in the list archives or in StackOverflow, so I thought I'd share what I came up with: >> >> >> <?xml version="1.0" encoding="UTF-8"?> >> <xsl:stylesheet xmlns:xsl=http://www.w3.org/1999/XSL/Transform >> xmlns:xs=http://www.w3.org/2001/XMLSchema >> exclude-result-prefixes="#all" >> version="2.0"> >> <xsl:output indent="yes"/> >> >> >> <!-- regex that defines what a "word" is --> >> <xsl:param name="word-pattern" select="'(\w+)'"/> >> >> >> <!-- identity transformation --> >> <xsl:template match="@*|node()"> >> <xsl:copy> >> <xsl:apply-templates select="@*|node()"/> >> </xsl:copy> >> </xsl:template> >> >> >> <!-- shuffle words in each text() element --> >> <xsl:template match="text()[not(ancestor::pre)]"> >> <!-- get the list of words in this block of text --> >> <xsl:variable name="words" as="node()*"> >> <xsl:analyze-string select="." regex="{$word-pattern}"> >> <xsl:matching-substring> >> <word><xsl:value-of select="."/></word> >> </xsl:matching-substring> >> </xsl:analyze-string> >> </xsl:variable> >> >> <!-- perturb the word order --> >> <xsl:variable name="shuffled-words" as="xs:string*"> >> <xsl:call-template name="pick-random-item"> >> <xsl:with-param name="items" select="$words"/> >> </xsl:call-template> >> </xsl:variable> >> >> <!-- reform the string with the reordered words--> >> <xsl:analyze-string select="." regex="{$word-pattern}"> >> <xsl:matching-substring> >> <xsl:variable name="this-position" select="position()"/> >> <xsl:value-of select="$shuffled-words[floor(($this-position + 1) div 2)]"/> >> </xsl:matching-substring> >> <xsl:non-matching-substring> >> <xsl:value-of select="."/> >> </xsl:non-matching-substring> >> </xsl:analyze-string> >> </xsl:template> >> >> >> <!-- XSLT item shuffler, borrowed from >> https://stackoverflow.com/questions/21953336/randomize-node-order-xslt --> >> <xsl:param name="initial-seed" select="123"/> >> <xsl:template name="pick-random-item"> >> <xsl:param name="items" /> >> <xsl:param name="seed" select="$initial-seed"/> >> <xsl:if test="$items"> >> <!-- generate a random number using the "linear congruential generator" algorithm --> >> <xsl:variable name="a" select="1664525"/> >> <xsl:variable name="c" select="1013904223"/> >> <xsl:variable name="m" select="4294967296"/> >> <xsl:variable name="random" select="($a * $seed + $c) mod $m"/> >> <!-- scale random to integer 1..n --> >> <xsl:variable name="i" select="floor($random div $m * count($items)) + 1"/> >> <!-- write out the corresponding item --> >> <xsl:copy-of select="$items[$i]"/> >> <!-- recursive call with the remaining items --> >> <xsl:call-template name="pick-random-item"> >> <xsl:with-param name="items" select="$items[position()!=$i]"/> >> <xsl:with-param name="seed" select="$random"/> >> </xsl:call-template> >> </xsl:if> >> </xsl:template> >> >> </xsl:stylesheet> >> >> >> Link to XSLT Fiddle here: https://xsltfiddle.liberty-development.net/nbiE1aZ/1 >> >> The approach is: >> >> 1. Call <xsl:analyze-string> to extract the words from a text() element. >> 2. Call a template that shuffles the words. >> 3. Call <xsl:analyze-string> (again) to substitute the shuffled words in place of the original words. >> >> Hopefully this is helpful if someone needs to solve a similar problem in the future! >> >> ----- >> Chris Papademetrious >> Tech Writer, Synopsys, Inc.
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] shuffling words in text c, Chris Papademetrious | Thread | [xsl] [ANN] XSLT 3 training - Septe, Liam R. E. Quin liam |
Re: [xsl] shuffling words in text c, Michael Kay mike@xxx | Date | Re: [xsl] shuffling words in text c, Martin Honnen martin |
Month |