Another note: People may want to generate not xslt-code, but pure XPath
code (and evaluate it with xsl:evaluate in XSLT, or using fn:load-xquery
module, if they don't have an xslt-capable host.
https://qt4cg.org/specifications/xpath-functions-40/Overview.html#func-load-x
query-module
On Fri, Jan 17, 2025 at 1:36b/PM Dimitre Novatchev <dnovatchev@xxxxxxxxx>
wrote:
> Hi Roger,
>
> > <axsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
> version="3.0">
> > <axsl:template match="/">
> > <axsl:for-each select="/passwds/passwd">
> > <axsl:variable name="passwd" select="."/>
> > <xsl:for-each select="/validation_tests/test">
> > <axsl:choose>
> > <axsl:when test="{xpath}">
> > <axsl:message>line <axsl:value-of
> select="position()"/>, <xsl:value-of select="message"/>: <axsl:value-of
> select="$passwd"/></axsl:message>
> > </axsl:when>
> > </axsl:choose>
> > </xsl:for-each>
> > </axsl:for-each>
> > </axsl:template>
> > </axsl:stylesheet>
>
> This seems rather unreadable to me, and I would definitely want to avoid
> having to debug two different transformations - too-inconvenient.
>
> What I would do instead:
>
> 1. Generate the new XSLT code as a string. This is more readable,
> because no <xsl:namespace-alias> directive is needed and we will be
using
> just/only the wellknown "xsl:" prefix.
> 2. Call the standard XPath fn:transform, passing to it as a parameter
> the generated string.
> https://www.w3.org/TR/xpath-functions-31/#func-transform
> 3. This can be combined with the "fill-in the blanks" approach, where
> the skeleton for the generated code is contained in an external file,
and
> only its (marked as) variable parts are dynamically replaced with
> calculated values.
>
> Also, this approach has the advantage that the xslt code generation can be
> coded not only in XSLT, but even in pure XPath 3.
>
> As they say, "just my 2c." :)
>
> Thanks,
> Dimitre
>
>
>
> On Fri, Jan 17, 2025 at 12:22b/PM Roger L Costello costello@xxxxxxxxx <
> xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
>
>> Hi Folks,
>>
>> Recently I was reading Brian Kernighan's new book on AWK, and it showed a
>> wicked cool AWK program that outputs an AWK program. Below is the AWK
>> program, followed by the equivalent XSLT program.
>>
>> The task is to run some checks on a password file. Here is a sample
>> password file:
>>
>> root:qyxRi2uVjrg:0:2::/:
>> jd:1L./v6iblzzNE:9:1:John Doe:/usr/jd:
>> jt:otxs1oToyvMQ:15:1:Jim Thomson:/usr/jt:
>> uucp:xutIBs2hKtcls:48:1:uucp daemon:/usr/lib/uucp:uucico
>> sm:xNqy//GDc8FFg:170:2:Sally Smith:/usr/sm:
>> a!f:aiopaIAjfaI:21:1:Fake Person:/usr/a!f:
>> jv::1:Jules Verne:/usr/jv:
>> ah:dsjkdAJ:34:1:Alexander Hamilton
>>
>> Fields within each line are delimited by a colon.
>>
>> The first field is the username. It should be alphanumeric. Check each
>> line to confirm that its username is alphanumeric.
>> The second field is an encrypted version of the password. The field
>> should not be empty. Check each line to confirm that it's not empty.
>> I won't discuss the other fields.
>> The third check confirms that each line has 7 fields.
>>
>>
>>
-----------------------------------------------------------------------------
---------------
>> AWK Version
>>
>>
-----------------------------------------------------------------------------
---------------
>> Here's an AWK expression to check whether a line does not have 7 fields:
>>
>> NF != 7
>>
>> [NF = Number of Fields, NF is a built-in function]
>>
>> Here's an AWK expression to check whether the second field is empty:
>>
>> $2 == ""
>>
>> [$1 denotes the first field, $2 denotes the second field, etc.]
>>
>> Here's an AWK expression to check whether the first field is not
>> alphanumeric:
>>
>> $1 ~ /[^A-Za-z0-9]/
>>
>> [tilda means "matches"; the stuff between slashes is a regex]
>>
>> Put the expressions into a file, along with a description:
>>
>> NF != 7 does not have 7 fields
>> $2 == "" no password
>> $1 ~ /[^A-Za-z0-9]/ nonalphanumeric user id
>>
>> The following AWK program inputs those expressions and outputs a program
>> that applies the expressions to each line of the password file:
>>
>> BEGIN { FS = "\t+" }
>> { printf("%s {\n\tprintf(\"line %%d, %s: %%s\\n\",NR,$0) }\n", $1, $2) }
>>
>> [FS = Field Separator. NR = Row Number, $0 denotes the entire line. If
>> you know the C printf statement you can probably figure out what that
>> printf is doing--it is outputting a printf]
>>
>> Run the AWK program; it generates this AWK program:
>>
>> NF != 7 {
>> printf("line %d, does not have 7 fields: %s\n",NR,$0) }
>> $2 == "" {
>> printf("line %d, no password: %s\n",NR,$0) }
>> $1 ~ /[^A-Za-z0-9]/ {
>> printf("line %d, nonalphanumeric user id: %s\n",NR,$0) }
>>
>> Now run that generated AWK program against the password file. It reveals
>> errors in the password file:
>>
>> line 6, nonalphanumeric user id: a!f:aiopaIAjfaI:21:1:Fake
>> Person:/usr/a!f:
>> line 7, does not have 7 fields: jv::1:Jules Verne:/usr/jv:
>> line 7, no password: jv::1:Jules Verne:/usr/jv:
>> line 8, does not have 7 fields: ah:dsjkdAJ:34:1:Alexander Hamilton
>>
>>
>>
-----------------------------------------------------------------------------
---------------
>> XSLT/XPath Version
>>
>>
-----------------------------------------------------------------------------
---------------
>> Format the password file as XML:
>>
>> <passwds>
>> <passwd>root:qyxRi2uVjrg:0:2::/:</passwd>
>> <passwd>jd:1L./v6iblzzNE:9:1:John Doe:/usr/jd:</passwd>
>> <passwd>jt:otxs1oToyvMQ:15:1:Jim Thomson:/usr/jt:</passwd>
>> <passwd>uucp:xutIBs2hKtcls:48:1:uucp
>> daemon:/usr/lib/uucp:uucico</passwd>
>> <passwd>sm:xNqy//GDc8FFg:170:2:Sally Smith:/usr/sm:</passwd>
>> <passwd>a!f:aiopaIAjfaI:21:1:Fake Person:/usr/a!f:</passwd>
>> <passwd>jv::1:Jules Verne:/usr/jv:</passwd>
>> <passwd>ah:dsjkdAJ:34:1:Alexander Hamilton</passwd>
>> </passwds>
>>
>> Create XPath expressions for the three checks and put the XPath
>> expressions into a file:
>>
>> <validation_tests>
>> <test>
>> <xpath>count(tokenize(.,':')) ne 7</xpath>
>> <message>does not have 7 fields</message>
>> </test>
>> <test>
>> <xpath>tokenize(.,':')[2] eq ''</xpath>
>> <message>no password</message>
>> </test>
>> <test>
>> <xpath>string-length(translate(tokenize(., ':')[1],
>> 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', '')) ne
>> 0</xpath>
>> <message>nonalphanumeric user id</message>
>> </test>
>> </validation_tests>
>>
>> This XSLT program inputs the XPath expressions file and outputs an XSLT
>> program that applies the XPath expressions:
>>
>> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>> xmlns:axsl="http://www.w3.org/1999/XSL/Transform/alias"
>> version="3.0">
>>
>> <xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>
>>
>> <xsl:template match="/">
>> <axsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>> version="3.0">
>> <axsl:template match="/">
>> <axsl:for-each select="/passwds/passwd">
>> <axsl:variable name="passwd" select="."/>
>> <xsl:for-each select="/validation_tests/test">
>> <axsl:choose>
>> <axsl:when test="{xpath}">
>> <axsl:message>line <axsl:value-of
>> select="position()"/>, <xsl:value-of select="message"/>: <axsl:value-of
>> select="$passwd"/></axsl:message>
>> </axsl:when>
>> </axsl:choose>
>> </xsl:for-each>
>> </axsl:for-each>
>> </axsl:template>
>> </axsl:stylesheet>
>> </xsl:template>
>> </xsl:stylesheet>
>>
>> Here is the XSLT it generates:
>>
>> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>> version="3.0">
>> <xsl:template match="/">
>> <xsl:for-each select="/passwds/passwd">
>> <xsl:variable name="passwd" select="."/>
>> <xsl:choose>
>> <xsl:when test="count(tokenize(., ':')) ne 7">
>> <xsl:message>line <xsl:value-of
>> select="position()"/>, does not have 7 fields: <xsl:value-of
>> select="$passwd"/></xsl:message>
>> </xsl:when>
>> </xsl:choose>
>> <xsl:choose>
>> <xsl:when test="tokenize(., ':')[2] eq ''">
>> <xsl:message>line <xsl:value-of
>> select="position()"/>, no password: <xsl:value-of
>> select="$passwd"/></xsl:message>
>> </xsl:when>
>> </xsl:choose>
>> <xsl:choose>
>> <xsl:when test="string-length(translate(tokenize(.,
>> ':')[1], 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
>> '')) ne 0">
>> <xsl:message>line <xsl:value-of
>> select="position()"/>, nonalphanumeric user id: <xsl:value-of
>> select="$passwd"/></xsl:message>
>> </xsl:when>
>> </xsl:choose>
>> </xsl:for-each>
>> </xsl:template>
>> </xsl:stylesheet>
>>
>> Run the generated XSLT program against the password file; these messages
>> are displayed:
>>
>> line 6, nonalphanumeric user id: a!f:aiopaIAjfaI:21:1:Fake
>> Person:/usr/a!f:
>> line 7, does not have 7 fields: jv::1:Jules Verne:/usr/jv:
>> line 7, no password: jv::1:Jules Verne:/usr/jv:
>> line 8, does not have 7 fields: ah:dsjkdAJ:34:1:Alexander Hamilton
>>
>>
>>
>
>
>
--
Cheers,
Dimitre Novatchev
---------------------------------------
Truly great madness cannot be achieved without significant intelligence.
---------------------------------------
To invent, you need a good imagination and a pile of junk
-------------------------------------
Never fight an inanimate object
-------------------------------------
To avoid situations in which you might make mistakes may be the
biggest mistake of all
------------------------------------
Quality means doing it right when no one is looking.
-------------------------------------
You've achieved success in your field when you don't know whether what
you're doing is work or play
-------------------------------------
To achieve the impossible dream, try going to sleep.
-------------------------------------
Facts do not cease to exist because they are ignored.
-------------------------------------
Typing monkeys will write all Shakespeare's works in 200yrs.Will they write
all patents, too? :)
-------------------------------------
Sanity is madness put to good use.
-------------------------------------
I finally figured out the only reason to be alive is to enjoy it.
|