Competency Generation XSLT - Process Documentation

Experimentation on competency formal grammar syntax rules and generation of competency data

General competency syntax for all scopes:

Screen capture of competency grammar

Click Here to see the Full Interactive Competency Grammar Syntax Diagram

Table of Contents

1st Processing Stage: Competency Sentence Generation and Construction (Part 1. Non-Whole Numbers)

File Locations

The Input

Math K-5 Competency Input (from Math team - no sentence generation required)

XSLT Generator - raw unformatted XML file with competencies for each scope EXCEPT whole numbers:

XML Output

The XML output file for each scope competency is located within their respective scope folder names in this directory:

NOTE: not all of the scope comp XML files have been fully processed, so not all of them are ready for the next stage of conversion. See below.

NOTE: *so far only the K-5 scopes have been fully processed with transitive IDs and transitive parent competencies, which can be found here:

Fully Prepared XML Seed Data Output (K-5) (not wholenums):

About the XSLT Competency Generators

The XSLT generator scripts have two basic components:

  1. The sentenceWriter Named Template Function handles the sentence construction:

  2. The Sentence Generator xsl:template Rules (sends chunks to the Sentence writer):

    Screen capture of competency grammar

    Click Here to see the Full Interactive Competency Grammar Syntax Diagram

Global Component Params:

These are the <xsl:params> that capture the buckets competency component strings, based on the name of the container element.

<xsl:param name="formal_process" as="xs:string" select="'formal_process'"/> <xsl:param name="knowledge_process" as="xs:string" select="'knowledge_process'"/> <xsl:param name="processPred" as="xs:string" select="'processPred'"/> <xsl:param name="specificObject" as="xs:string" select="'specific_object'"/> <xsl:param name="math_operation" as="xs:string" select="'math_operation'"/> <xsl:param name="object" as="xs:string" select="'quant'"/> <xsl:param name="notationObject" as="xs:string" select="'notationObject'"/>

NOTE:

Generating Parent Competencies and Low-Level Competencies - Grouped Hierarchies

All subsequent stages of processing the seed data depend upon a specific hierarchy of nested competency group nodes in order to properly identify, capture, and transform a parent competency, a sub-parent competency, and low-level competencies.

Here's an abridged overview of the XML data structure our competency generator XSLT should produce:

NOTE: Following example is from wholenumsNestedParentOutput.xml - no other scopes will have kp-mathop-sp knowledge subprocess 2nd-level parent nodes, but some will still contain the "fp" formal process notationParent sub-parent level nodes.

<xml> <parent group="fp-pp"> <parentGroup lvl="1> <!-- collection of top-level parent competencies here --> </parentGroup> <compGroup> <!-- collection of 1st-level specific competencies here --> </compGroup> <notationParent group="fp-pp-no"> <parentGroup lvl="2"> <!-- collection of 2nd-level parent competencies here --> </parentGroup> <compGroup> <!-- collection of lowest-level specific competencies here --> </compGroup> </notationParent> </parent> <parent group="kp-mathop"> <parentGroup lvl="1> <!-- collection of top-level parent competencies here --> </parentGroup> <compGroup> <!-- collection of 1st-level specific competencies here --> </compGroup> <subParent group="kp-mathop-sp"> <parentGroup lvl="2"> <!-- collection of 2nd-level parent competencies here --> </parentGroup> <compGroup> <!-- collection of lowest-level specific competencies here --> </compGroup> </notationParent> </parent> </xml>

Example:

<xsl:template match="/"> <xml> <xsl:variable name="chunk1"> <!-- place for-each key scope filter selector and <xsl:sequence> selecting required chunk's global $param--> </xsl:variable> <xsl:variable name="chunk2"> <!-- ^^ --> </xsl:variable> <xsl:variable name="scopeString" select="'involving [Scope Name Here]'"/> <xsl:variable name="subScopeString"> <!-- place an xsl:sequence retrieving each child node of the 'subScope' parent bucket to capture sub-scope strings --> </xsl:variable> <parent group="combo-id-here"> <parentGroup lvl="1"> <xsl:call-template name="parentWriter"> <xsl:with-param name="param1" select="$chunk1"/> <xsl:with-param name="param2" select="$chunk2"/> </xsl:call-template> </parentGroup> <compGroup> <xsl:call-template name="sentenceWriter> <xsl:with-param name="param1" select="$chunk1"/> <xsl:with-param name="param2" select="$chunk2"/> <xsl:with-param name="scopeParam" select="$scopeString"/> <xsl:with-param name="subScopeParam" select="$subScopeString"/> </xsl:call-template> </compGroup> <!-- variables for filtering notation object or knowledge subprocess word chunk buckets here using key(...) INTERSECT key(...) to filter on both scope key and the other desired filter key, for next level of parent/comp groups --> <subParent group="combo-id-here"> <parentGroup lvl="2"> <xsl:call-template name="parentWriter"> <!-- xsl:with-params for parent comp chunks here --> </xsl:call-template> </parentGroup> <compGroup> <!-- xsl:call-template sentenceWriter with lowest-level comp chunks selected here --> </compGroup> </subParent> </parent> </xml> </xsl:template>

Scope Filtering

Scope Key:

<xsl:key name="scopes" match="string" use="@class ! tokenize(., '\s+')"/>

Global Scope Params:

These params are used when the scope key is called upon in a competency component variable within a given scope's template rules.

<!-- K-5 --> <xsl:param name="int" as="xs:string" select="'int'"/> <xsl:param name="rational" as="xs:string" select="'rational'"/> <xsl:param name="algexp" as="xs:string" select="'algexp'"/> <xsl:param name="numexp" as="xs:string" select="'numexp'"/> <!-- ** Whole Numbers ** (see note) --> <xsl:param name="wholenum" as="xs:string" select="'wholenum'"/> <!-- Other scopes --> <xsl:param name="complex" as="xs:string" select="'complex'"/> <xsl:param name="imag" as="xs:string" select="'imag'"/> <xsl:param name="plane" as="xs:string" select="'plane'"/> <xsl:param name="space" as="xs:string" select="'space'"/> <xsl:param name="expect" as="xs:string" select="'expect'"/> <xsl:param name="real" as="xs:string" select="'real'"/> <xsl:param name="unit" as="xs:string" select="'unit'"/> <xsl:param name="vector" as="xs:string" select="'vector'"/> <!-- scopes in progress --> <!-- scopes not filtered yet --> <xsl:param name="matrix" as="xs:string" select="'matrix'"/> <xsl:param name="infinite" as="xs:string" select="'infinite'"/> <xsl:param name="random" as="xs:string" select="'random'"/> <xsl:param name="prob" as="xs:string" select="'prob'"/>

NOTE:

xsl:key Generator Implementations:

How to use xsl:key and xsl:param to filter specific scope strings/handling instructions:

The XSLT sentence generator requires an xsl:variable that calls on a global xsl:key, and applies a key-value xsl:param set to a string value of the scope or special filtering attribute.

Example of a Filtering Variable using an xsl:key:

Say you want to output a set competency sentences in the Imaginary Numbers scope that contains a Knowledge Process (knowledgeProcess strings in the input xml) and a Process Predicate(processPred strings in input xml).

Knowledge Process component variable:

<xsl:variable name="KPimag" as="element()+"> <xsl:for-each select="key('scopes', $imag)"> <xsl:sequence select=".[parent::* ! name() = $knowledge_process]"/> </xsl:for-each> </xsl:variable>

Process Predicate component variable:

<xsl:variable name="PrPredimag" as="element()+"> <xsl:for-each select="key('scopes', $imag)"> <xsl:sequence select=".[parent::* ! name() = $processPred]"/> </xsl:for-each> </xsl:variable>

Now, to apply those filtering rules to the Sentence Writer template function, we must call on that template and send to it these variables in the order in which they should occur in the sentence. To do that, we apply xsl:with-param elements for each component variable within an xsl:call-template that calls on our sentence writer template:

<xsl:call-template name="sentenceWriter"> <xsl:with-param name="param1" select="$KPimag"/> <xsl:with-param name="param2" select="$PrPredimag"/> </xsl:call-template>

How to filter a competency component by string AND scope - combining two xsl:keys with INTERSECT

There are some competency sentence scenarios where the presence of one sentence component determines whether or not certain strings within another component will output. i.e., only a select few strings within a given component set will output when a different component is generated in that sentence group as well.

In these cases, we must call on two xsl:keys using the intersect conjunction when creating the co-dependent component variable in order to tell the generator to filter that component using BOTH parameters.

Scopes where xsl:key intersection filtering occurs

Example: Scope Key INTERSECT Notation Key

In scopes that can have a Notation Object component in their competency sentences, the presence of the Notation object requires there to be a Formal Process in the sentence - but only TWO of the Formal Process strings can be output with a notation object: "Read" and "Write".

In the input XML, those two string elements contain an @subclass="notation" attribute value alongside the @class attribute for scope filtering. (See the Notation Object Filtering - Special Formal Process String Keys section below for more details how the notation xsl:key works.)

Say you want to generate competencies in the Integers scope that contain a Formal Process (keyed to notation), a Process Predicate, and a Notation Object.

To apply both keys to the Formal Process variable, you need to add the intersect conjunction with the second key-value pair to the xsl:for-each select="key('scopes', $int)" selector within the FPint (Formal Process Integers) variable:

<xsl:variable name="FPint" as="element()+"> <xsl:for-each select="key('scopes', $int) intersect key('notationKey', $notation)"> <xsl:sequence select=".[parent::* ! name() = $formal_process]"/> </xsl:for-each> </xsl:variable>

Since only the Formal Process component is affected by the presence of the Notation Object, that is the only variable you will need to use both the Scope Key and the Notation Key. All other components remain filtered through ONLY the $imag param scope key:

<xsl:variable name="FPint" as="element()+"> <xsl:for-each select="key('scopes', $int) intersect key('notationKey', $notation)"> <xsl:sequence select=".[parent::* ! name() = $formal_process]"/> </xsl:for-each> </xsl:variable> <xsl:variable name="PrPredint" as="element()+"> <xsl:for-each select="key('scopes', $int)"> <xsl:sequence select=".[parent::* ! name() = $processPred]"/> </xsl:for-each> </xsl:variable> <xsl:variable name="NO_int" as="element()+"> <xsl:for-each select="key('scopes', $int)"> <xsl:sequence select=".[parent::* ! name() = $notationObject]"/> </xsl:for-each> </xsl:variable>

Sentence Construction Combination Type Legend:

Formal Process Branch

Knowledge Process Branch

Part 2. Whole Numbers Scope Competency Generation - Separate Workflow

Whole Numbers Scope competency syntax:

Screen capture of whole numbers competency grammar

Click Here to see the Full Interactive Competency Grammar Syntax Diagram

Given that the Whole Numbers scope is so vast, and contains a different sentence structure and set of grammar rules than the other scopes, Whole Numbers has its own special XSLT generator that will apply different filtering rules to output seed data for each Whole Numbers subscope set.

Whole Numbers Sub-Scope Set:

File Locations

The Input

Whole Numbers Sentence Combination Group Legend

The groups of competencies are separated by whichever competency sentence components a given group contains. They are named accordingly:

Formal Process Branch

Knowledge Process Branch

Global Whole Numbers Component Params:

<xsl:param name="formal_process" as="xs:string" select="'formalProcess'"/> <xsl:param name="knowledge_process" as="xs:string" select="'knowledgeProcess'"/> <xsl:param name="knowledge_subprocess" as="xs:string" select="'knowledgeSubprocess'"/> <xsl:param name="processPred" as="xs:string" select="'processPred'"/> <xsl:param name="math_operation" as="xs:string" select="'mathOperation'"/> <xsl:param name="object" as="xs:string" select="'quant'"/> <xsl:param name="notationObject" as="xs:string" select="'notationObject'"/>

Wholenums xsl:key Filtering

Scope Key:

<xsl:key name="scopes" match="string" use="@class ! tokenize(., '\s+')"/>

Scope Param:

<xsl:param name="wholenum" as="xs:string" select="'wholenum'"/>

Notation Object Filtering - Special Formal Process String Keys

Since only two of the formalProcess strings will occur with a Notation Object string in the Whole Numbers Competency sentences, the Formal process string elements have attributes which define whether or not they go with a notation object, to be picked up by the following keys.

Specific Formal Process + Notation String Key:

<xsl:key name="notationKey" match="string" use="@subclass ! normalize-space()"/>

Subclass Notation Params:

<xsl:param name="notation" as="xs:string" select="'notation'"/> <xsl:param name="noNot" as="xs:string" select="'noNot'"/>

How to use Notation Object key to filter Formal Process strings:

The Notation key works the same way that the scope filtering key does. Here's an example of generating a set of Whole Numbers competency sentences that contain a Formal Process, a Process Predicate, and a Notation Object.

<xsl:variable name="FP_notation" as="element()+"> <xsl:for-each select="key('notationKey', $notation)"> <xsl:sequence select=".[parent::* ! name() = $formal_process]"/> </xsl:for-each> </xsl:variable> <xsl:variable name="PrPred" as="element()+"> <xsl:for-each select="key('scopes', $wholenum)"> <xsl:sequence select=".[parent::* ! name() = $processPred]"/> </xsl:for-each> </xsl:variable> <xsl:variable name="NO" as="element()+"> <xsl:for-each select="key('scopes', $wholenum)"> <xsl:sequence select=".[parent::* ! name() = $notationObject]"/> </xsl:for-each> </xsl:variable>

Notice how the variable for formalProcess uses the notationKey key name instead of scopes, and calls on the $notation global parameter to grab only the formalProcess strings with a notation attribute value. If you wanted to grab all of the formalProcess strings that do NOT go with a notation object, you'd call the $noNot param in that key instead.

Then, you call on the sentenceWriter template and apply those variables as ordered params using xsl:with-param, just as you would with the scopes variables:

<xsl:call-template name="sentenceWriter"> <xsl:with-param name="param1" as="element()+" select="$FP_notation"/> <xsl:with-param name="param2" as="element()+" select="$PrPred"/> <xsl:with-param name="param3" as="element()+" select="$NO"/> </xsl:call-template>

2nd Processing Stage: Seed Data JSON-Structure Conversion

File Locations

The Input:

The JSON-Structure Converter XSLTs:

Formatted JSON-Strucured XML Output:

About the JSON-Structure Converters

Structure Transformation Example

The JSON-Structure Converter XSLT takes this input:

<componentSentence> <formalProcess>Read</formalProcess> <processPred>Numerical Expressions</processPred> <scopeName>involving Integers</scopeName> <notationObject>in Proportional Notation</notationObject> </componentSentence>

... and transforms it into this structure, implementing a portion current node's transitive ID by counting all of the preceding competecies from the same tree-level:

<competency> <Token>read-numerical-expressions-involving-integers-in-proportional-notation</Token> <tID>203</tID> <Creator>Big Ideas Learning</Creator> <Title> <lang>en-us</lang> <text>Read Numerical Expressions involving Integers in Proportional Notation</text> </Title> <Definition> <lang>en-us</lang> <text>Read Numerical Expressions involving Integers in Proportional Notation</text> </Definition> </competency>

Final Processing Stage: XML-to-JSON Conversion

File Locations

The Input

the input XML files for this final conversion XSLT are the same as the output for the Structure Conversion XSLT above.

The XML-JSON Converter XSLT

Final JSON Output

About the XML-JSON Converter XSLT

This is the final processing stage, which transforms the formatted XML output from the previous XSLT into JSON.

The XML-to-JSON converter also completes the production of transitive IDs and tFrom transitive parent IDs.

Example of JSON transformation

Turning this...

<competency> <Token>read-numerical-expressions-involving-integers-in-proportional-notation</Token> <tID>203</tID> <Creator>Big Ideas Learning</Creator> <Title> <lang>en-us</lang> <text>Read Numerical Expressions involving Integers in Proportional Notation</text> </Title> <Definition> <lang>en-us</lang> <text>Read Numerical Expressions involving Integers in Proportional Notation</text> </Definition> </competency>

into this:

{ "Token": "read-numerical-expressions-involving-integers-in-proportional-notation", "tID": "0.0-203", "tFrom": "0.0", "Creator": "Big Ideas Learning", "Title": [{ "lang": "en-us", "text": "Read Numerical Expressions involving Integers in Proportional Notation" }], "Definition": [{ "lang": "en-us", "text": "Read Numerical Expressions involving Integers in Proportional Notation" }] },

Developer Notes

Considerations

Final Data Implementation

Scope competencies generated so far

K-5 focus lens:

others

scopes still to do:

Tools

BNFgen

Railroad Syntax Diagram Generator

Table of Contents