Subject: Re: [xsl] I love programs that output programs From: "Dimitre Novatchev dnovatchev@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> Date: Fri, 17 Jan 2025 21:36:43 -0000 |
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
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] I love programs that outp, russurquhart1@xxxxxx | Thread | Re: [xsl] I love programs that outp, Roger L Costello cos |
Re: [xsl] I love programs that outp, russurquhart1@xxxxxx | Date | Re: [xsl] I love programs that outp, Dimitre Novatchev dn |
Month |