Skip to content

Commit

Permalink
Merge pull request #3 from galtm/uuid-util
Browse files Browse the repository at this point in the history
UUID and message handling code copied from OSCAL repo
  • Loading branch information
aj-stein-nist authored Mar 15, 2023
2 parents 519f423 + ff9c513 commit 58ee15a
Show file tree
Hide file tree
Showing 9 changed files with 652 additions and 0 deletions.
8 changes: 8 additions & 0 deletions message-handler/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# XSLT Message Handler

This directory contains XSLT named templates for handling error and warning messages:

* `x3f:message-handler` template: Emit message to console, or output processing instruction instead.



35 changes: 35 additions & 0 deletions message-handler/message-handler.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:x3f="http://csrc.nist.gov/ns/xslt3-functions"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">

<xsl:param name="x3f:returns_pi" as="xs:boolean" select="false()"/>

<xsl:template name="x3f:message-handler">
<xsl:param name="text" as="xs:string"/>
<xsl:param name="message-type" as="xs:string?"/><!-- e.g., 'Error', 'Warning' -->
<xsl:param name="error-code" as="xs:string?"/>
<xsl:param name="terminate" as="xs:boolean" select="false()"/>
<xsl:param name="returns_pi" as="xs:boolean" select="$x3f:returns_pi"/>
<xsl:variable name="joined-string" as="xs:string"
select="string-join(($message-type, $error-code, $text),': ')"/>
<xsl:choose expand-text="yes">
<xsl:when test="$returns_pi">
<xsl:processing-instruction name="message-handler">{
if ($terminate) then 'Terminating ' else ''
}{
$joined-string
}</xsl:processing-instruction>
<!-- Above, line break inside the text value template instead of outside it
prevents the output PI from including the line break. -->
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="{$terminate}">{$joined-string}</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

</xsl:stylesheet>
71 changes: 71 additions & 0 deletions message-handler/tests/message-handler.xspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<x:description
xmlns:x="http://www.jenitennison.com/xslt/xspec"
xmlns:x3f="http://csrc.nist.gov/ns/xslt3-functions"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
stylesheet="../message-handler.xsl"
xslt-version="3.0">

<x:param name="x3f:returns_pi" as="xs:boolean" select="true()"/>

<x:scenario label="Tests for x3f:message-handler template">
<x:scenario label="Call with text, type, and code">
<x:call template="x3f:message-handler">
<x:param name="text" select="'message text'"/>
<x:param name="message-type" select="'Warning'"/>
<x:param name="error-code" select="'ERR1'"/>
</x:call>
<x:expect label="PI indicating type, code, and text">
<?message-handler Warning: ERR1: message text?>
</x:expect>
</x:scenario>
<x:scenario label="Call with text and type only">
<x:call template="x3f:message-handler">
<x:param name="text" select="'message text'"/>
<x:param name="message-type" select="'Warning'"/>
</x:call>
<x:expect label="PI indicating type and text">
<?message-handler Warning: message text?>
</x:expect>
</x:scenario>
<x:scenario label="Call with text and code only">
<x:call template="x3f:message-handler">
<x:param name="text" select="'message text'"/>
<x:param name="error-code" select="'ERR1'"/>
</x:call>
<x:expect label="PI indicating code and text">
<?message-handler ERR1: message text?>
</x:expect>
</x:scenario>
<x:scenario label="Call with text only">
<x:call template="x3f:message-handler">
<x:param name="text" select="'message text'"/>
</x:call>
<x:expect label="PI indicating text">
<?message-handler message text?>
</x:expect>
</x:scenario>
<x:scenario label="Call with text and type only, with terminate=true: ">
<x:scenario label="Check that message really terminates transform" catch="yes">
<x:call template="x3f:message-handler">
<x:param name="text" select="'message text'"/>
<x:param name="message-type" select="'Error'"/>
<x:param name="terminate" select="true()"/>
<x:param name="returns_pi" select="false()"/>
</x:call>
<x:expect label="Error" test="$x:result instance of map(*) and $x:result('err') instance of map(*)"/>
</x:scenario>
<x:scenario label="Check PI">
<x:call template="x3f:message-handler">
<x:param name="text" select="'message text'"/>
<x:param name="message-type" select="'Error'"/>
<x:param name="terminate" select="true()"/>
<x:param name="returns_pi" select="true()"/>
</x:call>
<x:expect label="PI indicating type and text, where type is 'Terminating Error'">
<?message-handler Terminating Error: message text?>
</x:expect>
</x:scenario>
</x:scenario>
</x:scenario>
</x:description>
11 changes: 11 additions & 0 deletions random-util/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Utilities for Generating Pseudorandom Numbers

This directory contains XSLT functions and named templates for working with pseudorandom numbers:

* `x3f:determine-uuid` template: Return UUID string based on choice of generation options.
* `x3f:make-uuid` function: Return one v4 UUID.
* `x3f:make-uuid-sequence` function: Return sequence of v4 UUIDs.
* `x3f:make-random-string-sequence` function: Return sequence of strings based on user-specified pattern.



122 changes: 122 additions & 0 deletions random-util/random-util.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<?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"
xmlns:math="http://www.w3.org/2005/xpath-functions/math" exclude-result-prefixes="#all"
xmlns:x3f="http://csrc.nist.gov/ns/xslt3-functions" version="3.0">

<!-- from the spec https://www.w3.org/TR/xpath-functions-31/#func-random-number-generator
declare %public function x3f:random-sequence($length as xs:integer) as xs:double* {
x3f:random-sequence($length, fn:random-number-generator())
};
declare %private function x3f:random-sequence($length as xs:integer,
$G as map(xs:string, item())) {
if ($length eq 0)
then ()
else ($G?number, x3f:random-sequence($length - 1, $G?next()))
};
x3f:random-sequence(200);
v4 UUID
hex fields 8 4 4 4 12
place 13 = 4
place 17 = 8-b
-->
<xsl:output indent="yes"/>

<!-- Set $germ to a string for reproducible outputs of x3f:make-uuid.
Pass in a blind value - and don't save it - for irreproducible outputs. -->

<xsl:param name="germ" select="current-dateTime() || document-uri(/)"/>

<!-- for testing random number features -->
<xsl:template match="/" name="xsl:initial-template" expand-text="true">
<!--<uuid><xsl:value-of select="uuid:randomUUID()" xmlns:uuid="java:java.util.UUID"/></uuid>-->
<randomness>
<now>{ x3f:make-uuid(current-dateTime()) }</now>
<germ>{ x3f:make-uuid($germ) }</germ>
<a>{ x3f:make-uuid('a') }</a>
<a>{ x3f:make-uuid('a') }</a>
<b>{ x3f:make-uuid('b') }</b>
<ten>
<xsl:for-each select="x3f:make-uuid-sequence($germ, 10)">
<uuid>{ . }</uuid>
</xsl:for-each>
</ten>
</randomness>
</xsl:template>

<!-- x3f:make-uuid produces one v4 UUID. Output is repeatable for a given seed.
If the random-number-generator() function is not available,
this function returns an empty sequence. -->
<xsl:function name="x3f:make-uuid" as="xs:string?">
<xsl:param name="seed" as="item()"/>
<xsl:sequence select="x3f:make-uuid-sequence($seed, 1)"/>
</xsl:function>

<!-- x3f:make-uuid-sequence produces a sequence of $seq-length v4 UUIDs.
Output is repeatable for a given seed. If the random-number-generator()
function is not available, this function returns an empty sequence. -->
<xsl:function name="x3f:make-uuid-sequence" as="xs:string*">
<xsl:param name="seed" as="item()"/>
<xsl:param name="seq-length" as="xs:integer"/>
<xsl:variable name="uuid-v4-template" as="xs:string">________-____-4___-=___-____________</xsl:variable>
<!-- a847eaab-cec8-41bd-98e2-02d02900b554 -->
<xsl:sequence select="x3f:make-random-string-sequence($seed, $seq-length, $uuid-v4-template)"/>
</xsl:function>

<!-- x3f:make-random-string-sequence produces a sequence of $seq-length strings.
The $template parameter specifies the pattern of characters in each
string, where:
* '_' becomes a random hex value 0-9a-f
* '=' becomes one of '8','9','a','b' at random
* Any other character is copied to the output string
Output is repeatable for a given seed. If the random-number-generator()
function is not available, this function returns an empty sequence. -->
<xsl:function name="x3f:make-random-string-sequence" as="xs:string*">
<xsl:param name="seed" as="item()"/>
<xsl:param name="seq-length" as="xs:integer"/>
<xsl:param name="template" as="xs:string"/>
<xsl:sequence use-when="function-available('random-number-generator')">
<xsl:variable name="PRNG" as="map(xs:string, item())" select="random-number-generator($seed)"/>
<xsl:variable name="template-length" as="xs:integer" select="string-length($template)"/>
<xsl:variable name="template-char-seq" as="xs:string*"
select="$template ! string-to-codepoints(.) ! codepoints-to-string(.)"/>
<!-- Draw one long stream from PRNG over sequence of characters in concatenated template,
advancing state in each iteration. -->
<xsl:variable name="random-chars" as="xs:string">
<xsl:value-of>
<xsl:iterate select="for $idx in (1 to $seq-length) return $template-char-seq">
<xsl:param name="PRNG" as="map(xs:string, item())" select="$PRNG"/>
<xsl:apply-templates select="current()" mode="uuid-char">
<xsl:with-param name="PRNG" select="$PRNG"/>
</xsl:apply-templates>
<xsl:next-iteration>
<xsl:with-param name="PRNG" select="$PRNG?next()"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:value-of>
</xsl:variable>
<!-- Divide $random-chars into nonoverlapping strings:
$seq-length of them, each of length $template-length. -->
<xsl:sequence select="for $idx in (0 to $seq-length - 1)
return substring($random-chars, 1 + $idx * $template-length, $template-length)"/>
</xsl:sequence>
</xsl:function>

<xsl:variable name="hex-digits" select="tokenize('0 1 2 3 4 5 6 7 8 9 a b c d e f', ' ')"/>

<xsl:template match=".[. = '_']" mode="uuid-char">
<xsl:param name="PRNG" as="map(xs:string, item())"/>
<xsl:sequence select="$PRNG?permute($hex-digits)[1]"/>
</xsl:template>

<xsl:template match=".[. = '=']" mode="uuid-char">
<xsl:param name="PRNG" as="map(xs:string, item())"/>
<xsl:sequence select="$PRNG?permute(('8', '9', 'a', 'b'))[1]"/>
</xsl:template>

</xsl:stylesheet>
Loading

0 comments on commit 58ee15a

Please sign in to comment.