. "$BST_LIB" require xsltproc libxslt/present # libxslt — the GNOME XSLT 1.0 processor. xsltproc is the CLI driver over # libxslt + libexslt; libxml2 (already on this image) supplies the parser and # XPath engine underneath, so this suite is the transformation layer on top of # what 62-libxml2.test already covers. # # Everything is generated into $TMPDIR: the suite needs no data/ payload, and a # short path matters because several xsltproc diagnostics quote the filename. t=${TMPDIR:-/tmp}/bst-libxslt.$$ mkdir -p "$t" || { bst_notok libxslt/tmpdir "cannot create $t"; exit 0; } # --- payloads ---------------------------------------------------------------- cat > "$t/doc.xml" <<'EOF' Godel Escher BachHofstadter29.95 ContactSagan7.50 BlindsightWatts12.00 spaced text EOF # identity-ish: value-of, for-each, attribute access, text output cat > "$t/basic.xsl" <<'EOF' =| EOF # sorting, numbering, position()/last() cat > "$t/sort.xsl" <<'EOF' :(/) EOF # named templates, params, variables, recursion, choose/if cat > "$t/tmpl.xsl" <<'EOF' 1 fact10= cheap= EOF # keys, modes, apply-templates with select cat > "$t/key.xsl" <<'EOF' 1985: titles: , EOF # XPath 1.0 function library cat > "$t/xpath.xsl" <<'EOF' X-concat X-substring X-substring-before X-substring-after X-translate X-normalize X-strlen X-contains X-starts X-sum X-floor X-ceiling X-round X-count X-name X-ancestor X-following X-pred X-format X-boolean X-lang X-lang-root EOF # output methods / serialization cat > "$t/xmlout.xsl" <<'EOF' <raw& EOF cat > "$t/htmlout.xsl" <<'EOF' T

x

EOF cat > "$t/noxmldecl.xsl" <<'EOF' a < b EOF # stylesheet parameters cat > "$t/param.xsl" <<'EOF' P:/ EOF # import/include precedence cat > "$t/inc-base.xsl" <<'EOF' BASE- SHARED EOF cat > "$t/importer.xsl" <<'EOF' OVER-[] EOF # namespaces in the result tree cat > "$t/ns.xsl" <<'EOF' 1 EOF # EXSLT cat > "$t/exslt.xsl" <<'EOF' 12 E-nodeset E-tokenize E-tokenize2 E-replace E-padding E-max E-min E-abs E-distinct E-func EOF # deliberately broken stylesheet (unknown top-level XSL element in the XSL ns) cat > "$t/bad.xsl" <<'EOF' EOF # not well-formed XML printf '\n' > "$t/malformed.xml" # HTML input for --html cat > "$t/page.html" <<'EOF' Page

one

two EOF cat > "$t/html-in.xsl" <<'EOF' H:: EOF # infinite recursion, to prove --maxdepth is enforced rather than crashing cat > "$t/deep.xsl" <<'EOF' EOF # xsl:message terminate cat > "$t/terminate.xsl" <<'EOF' STOP-HERE EOF # --- 1. presence and identification ------------------------------------------ check libxslt/version xsltproc --version check_out libxslt/version-libxslt "libxslt 10143" xsltproc --version check_out libxslt/version-libexslt "libexslt" xsltproc --version check_out libxslt/version-libxml "compiled against libxml" xsltproc --version # --- 2. core XSLT 1.0 engine -------------------------------------------------- check_eq libxslt/basic-forEach \ 'b1=Godel Escher Bach|b2=Contact|b3=Blindsight|' \ "$(xsltproc "$t/basic.xsl" "$t/doc.xml" 2>/dev/null)" # xsl:sort reorders the iteration (position()/last() follow it) while xsl:number # keeps counting the node's place in the SOURCE tree — so the leading numbers # come out 2,3,1, which is the assertion worth making: it distinguishes the two. sorted=$(xsltproc "$t/sort.xsl" "$t/doc.xml" 2>/dev/null) check_eq libxslt/sort-numeric \ '2:Contact(1/3) 3:Blindsight(2/3) 1:Godel Escher Bach(3/3)' \ "$(printf '%s' "$sorted" | tr -s ' ' | sed 's/ $//')" tm=$(xsltproc "$t/tmpl.xsl" "$t/doc.xml" 2>/dev/null) check_eq libxslt/named-template-recursion 3628800 \ "$(printf '%s\n' "$tm" | sed -n 's/.*fact10=\([0-9]*\).*/\1/p')" check_eq libxslt/if-and-choose b2b3 \ "$(printf '%s\n' "$tm" | sed -n 's/.*cheap=\(.*\)$/\1/p')" kk=$(xsltproc "$t/key.xsl" "$t/doc.xml" 2>/dev/null) check_eq libxslt/key-lookup 2 "$(printf '%s\n' "$kk" | sed -n 's/^1985:\([0-9]*\).*/\1/p')" check_eq libxslt/apply-templates-mode 'God,Con,Bli,' \ "$(printf '%s\n' "$kk" | sed -n 's/.*titles:\(.*\)$/\1/p')" imp=$(xsltproc "$t/importer.xsl" "$t/doc.xml" 2>/dev/null) check_out libxslt/import-shared "SHARED" printf '%s' "$imp" check_out libxslt/import-override "OVER-Godel Escher Bach" printf '%s' "$imp" check_out libxslt/apply-imports "[BASE-Godel Escher Bach]" printf '%s' "$imp" # --- 3. the XPath 1.0 function library, one value per case -------------------- xp=$(xsltproc "$t/xpath.xsl" "$t/doc.xml" 2>/dev/null) xpv() { printf '%s\n' "$xp" | sed -n "s/^$1 //p"; } check_eq libxslt/xpath-concat abc "$(xpv X-concat)" check_eq libxslt/xpath-substring 234 "$(xpv X-substring)" check_eq libxslt/xpath-substring-before a "$(xpv X-substring-before)" check_eq libxslt/xpath-substring-after b "$(xpv X-substring-after)" check_eq libxslt/xpath-translate BAr "$(xpv X-translate)" check_eq libxslt/xpath-normalize-space 'spaced text' "$(xpv X-normalize)" check_eq libxslt/xpath-string-length 5 "$(xpv X-strlen)" check_eq libxslt/xpath-contains true "$(xpv X-contains)" check_eq libxslt/xpath-starts-with true "$(xpv X-starts)" check_eq libxslt/xpath-sum 49.45 "$(xpv X-sum)" check_eq libxslt/xpath-floor 3 "$(xpv X-floor)" check_eq libxslt/xpath-ceiling 4 "$(xpv X-ceiling)" check_eq libxslt/xpath-round 3 "$(xpv X-round)" check_eq libxslt/xpath-count 3 "$(xpv X-count)" check_eq libxslt/xpath-local-name book "$(xpv X-name)" check_eq libxslt/xpath-ancestor-axis catalog "$(xpv X-ancestor)" check_eq libxslt/xpath-following-sibling 2 "$(xpv X-following)" check_eq libxslt/xpath-predicate-index Blindsight "$(xpv X-pred)" check_eq libxslt/xpath-format-number '1,234,567.89' "$(xpv X-format)" check_eq libxslt/xpath-boolean-empty false "$(xpv X-boolean)" check_eq libxslt/xpath-lang true "$(xpv X-lang)" # lang() reads the context node's inherited xml:lang; at match="/" the context is # the root node, which inherits nothing — false is correct, not a miss. check_eq libxslt/xpath-lang-root false "$(xpv X-lang-root)" # --- 4. output methods and serialization -------------------------------------- xo=$(xsltproc "$t/xmlout.xsl" "$t/doc.xml" 2>/dev/null) check_out libxslt/out-xml-decl '' printf '%s' "$xo" check_out libxslt/out-copy-of '' printf '%s' "$xo" check_out libxslt/out-escaping '<raw&' printf '%s' "$xo" check_out libxslt/out-indent ' /dev/null) check_out libxslt/out-html-meta '' printf '%s' "$ho" no=$(xsltproc "$t/noxmldecl.xsl" "$t/doc.xml" 2>/dev/null) check_eq libxslt/out-omit-decl 0 "$(printf '%s\n' "$no" | grep -c '' printf '%s' "$no" nso=$(xsltproc "$t/ns.xsl" "$t/doc.xml" 2>/dev/null) check_out libxslt/ns-literal 'xmlns:e="urn:example"' printf '%s' "$nso" check_out libxslt/ns-xsl-element 'urn:other' printf '%s' "$nso" # --- 5. parameters and CLI surface -------------------------------------------- check_eq libxslt/param-default 'P:nobody/0' \ "$(xsltproc "$t/param.xsl" "$t/doc.xml" 2>/dev/null)" check_eq libxslt/stringparam 'P:world/0' \ "$(xsltproc --stringparam who world "$t/param.xsl" "$t/doc.xml" 2>/dev/null)" check_eq libxslt/param-xpath 'P:nobody/42' \ "$(xsltproc --param n 21 "$t/param.xsl" "$t/doc.xml" 2>/dev/null)" check_eq libxslt/param-xpath-string 'P:lit/0' \ "$(xsltproc --param who "'lit'" "$t/param.xsl" "$t/doc.xml" 2>/dev/null)" xsltproc --output "$t/out.txt" "$t/basic.xsl" "$t/doc.xml" 2>/dev/null check_out libxslt/cli-output 'b2=Contact' cat "$t/out.txt" check_eq libxslt/cli-stdin-doc 'b1=Godel Escher Bach|b2=Contact|b3=Blindsight|' \ "$(cat "$t/doc.xml" | xsltproc "$t/basic.xsl" - 2>/dev/null)" check_eq libxslt/cli-html-parser 'H:2:Page' \ "$(xsltproc --html "$t/html-in.xsl" "$t/page.html" 2>/dev/null)" check_out libxslt/cli-nonet 'b1=' xsltproc --nonet "$t/basic.xsl" "$t/doc.xml" check_out libxslt/cli-novalid 'b1=' xsltproc --novalid "$t/basic.xsl" "$t/doc.xml" check_out libxslt/cli-timing 'b1=' xsltproc --timing "$t/basic.xsl" "$t/doc.xml" check_out libxslt/cli-repeat 'b1=' xsltproc --repeat "$t/basic.xsl" "$t/doc.xml" # two documents on one command line are transformed independently (the text # output carries no trailing newline, so count occurrences, not lines) check_eq libxslt/cli-multi-doc 2 \ "$(xsltproc "$t/basic.xsl" "$t/doc.xml" "$t/doc.xml" 2>/dev/null | grep -o 'b3=Blindsight' | wc -l | tr -d ' ')" # --- 6. EXSLT (libexslt) ------------------------------------------------------ ex=$(xsltproc "$t/exslt.xsl" "$t/doc.xml" 2>/dev/null) exv() { printf '%s\n' "$ex" | sed -n "s/^$1 //p"; } check_eq libxslt/exslt-node-set 2 "$(exv E-nodeset)" check_eq libxslt/exslt-tokenize 3 "$(exv E-tokenize)" check_eq libxslt/exslt-tokenize-index b "$(exv E-tokenize2)" check_eq libxslt/exslt-replace 'a+b+c' "$(exv E-replace)" check_eq libxslt/exslt-padding '[....]' "$(exv E-padding)" check_eq libxslt/exslt-math-max 29.95 "$(exv E-max)" check_eq libxslt/exslt-math-min 7.5 "$(exv E-min)" check_eq libxslt/exslt-math-abs 7 "$(exv E-abs)" check_eq libxslt/exslt-set-distinct 2 "$(exv E-distinct)" check_eq libxslt/exslt-func 42 "$(exv E-func)" # date:date-time is not asserted for a value (it is the wall clock) but it must # produce a parseable ISO-8601 stamp, which exercises libexslt's date module and # the platform's time(2)/localtime(3) path. cat > "$t/date.xsl" <<'EOF' D Y W EOF dt=$(xsltproc "$t/date.xsl" "$t/doc.xml" 2>/dev/null) check_eq libxslt/exslt-date-year 2026 "$(printf '%s\n' "$dt" | sed -n 's/^Y //p')" if printf '%s\n' "$dt" | sed -n 's/^D //p' | grep -q '^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]'; then bst_ok libxslt/exslt-date-time else bst_notok libxslt/exslt-date-time "not ISO-8601: $(_bst_1line "$dt")" fi # --- 7. errors, exit codes and limits ----------------------------------------- check_rc libxslt/err-bad-xpath 5 xsltproc "$t/bad.xsl" "$t/doc.xml" check_rc libxslt/err-malformed-doc 6 xsltproc "$t/basic.xsl" "$t/malformed.xml" check_rc libxslt/err-missing-doc 6 xsltproc "$t/basic.xsl" "$t/nosuch.xml" check_rc libxslt/err-missing-xsl 4 xsltproc "$t/nosuch.xsl" "$t/doc.xml" check_rc libxslt/err-terminate 10 xsltproc "$t/terminate.xsl" "$t/doc.xml" # the message text must reach stderr — asserted separately from the rc, since # check_out also requires rc=0 and a terminate deliberately exits 10 tmsg=$(xsltproc "$t/terminate.xsl" "$t/doc.xml" 2>&1) case "$tmsg" in *STOP-HERE*) bst_ok libxslt/err-terminate-msg ;; *) bst_notok libxslt/err-terminate-msg "$(_bst_1line "$tmsg")" ;; esac # runaway recursion must be caught by the depth limiter, not by dying: xsltproc # reports the failure and exits non-zero, and it must still be < 128 (i.e. not a # signal death) — on this arm an unbounded recursion is the thing most likely to # take the whole runtime down rather than the program. out=$(xsltproc --maxdepth 200 "$t/deep.xsl" "$t/doc.xml" 2>&1); rc=$? if [ "$rc" -ne 0 ] && [ "$rc" -lt 128 ]; then bst_ok libxslt/maxdepth-enforced else bst_notok libxslt/maxdepth-enforced "rc=$rc $(_bst_1line "$out")"; fi check_out libxslt/maxdepth-message 'recursion' printf '%s' "$out" # --- 8. libexslt really is linked in, not merely referenced ------------------- # # This arm links everything statically, so there is no libexslt.so to look for — # the question "did libexslt make it into the binary" is answered by asking the # binary what it registered at start-up. check_out libxslt/dumpextensions-runs 'Registered XSLT Extensions' xsltproc --dumpextensions check_out libxslt/dumpextensions-exslt '{http://exslt.org/common}node-set' xsltproc --dumpextensions check_out libxslt/dumpextensions-math '{http://exslt.org/math}sqrt' xsltproc --dumpextensions check_out libxslt/dumpextensions-str '{http://exslt.org/strings}split' xsltproc --dumpextensions rm -rf "$t"