Skip to content

Commit

Permalink
Much progress especially on usnistgov#51 - XML to JSON converter gene…
Browse files Browse the repository at this point in the history
…rator, including XML to supermodel, supermodel to JSON
  • Loading branch information
wendellpiez committed Jun 11, 2020
1 parent 74a7d6d commit 67c7ddd
Show file tree
Hide file tree
Showing 8 changed files with 365 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<map xmlns="http://csrc.nist.gov/ns/oscal/metaschema/1.0"
namespace="http://csrc.nist.gov/metaschema/ns/everything"
prefix="http://csrc.nist.gov/metaschema/ns/everything">
<model xmlns="http://csrc.nist.gov/ns/oscal/metaschema/1.0"
root-at="EVERYTHING"
namespace="http://csrc.nist.gov/metaschema/ns/everything"
prefix="everything">
<assembly scope="global" key="EVERYTHING" gi="EVERYTHING">
<flag as-type="string" scope="global" key="id" gi="id"/>
<field scope="global" key="field-1only" gi="field-1only">
Expand All @@ -13,23 +14,23 @@
<flag as-type="string" scope="global" key="id" gi="id"/>
<value as-type="string" key="CUSTOM-VALUE-KEY"/>
</field>
<group key="groupable-fields" gi="groupable-fields">
<group key="groupable-fields">
<field scope="global" gi="field-groupable">
<value as-type="string" key="STRVALUE"/>
</field>
</group>
<group key="wrapped-fields" gi="wrapped-fields">
<group key="wrapped-fields" gi="wrapped-fields" group-json="ARRAY">
<field scope="global" gi="field-wrappable">
<value as-type="string" key="STRVALUE"/>
</field>
</group>
<group key="keyed-fields" gi="keyed-fields" json-key-flag="id">
<group key="keyed-fields" group-json="BY_KEY" json-key-flag="id">
<field scope="global" gi="field-by-key" json-key-flag="id">
<flag as-type="string" scope="global" key="id" gi="id"/>
<value as-type="string" key="STRVALUE"/>
</field>
</group>
<group key="dynamic-value-key-fields" gi="dynamic-value-key-fields">
<group key="dynamic-value-key-fields">
<field scope="global" gi="field-dynamic-value-key">
<flag as-type="string" scope="global" key="id" gi="id"/>
<value as-type="string" key-flag="id"/>
Expand All @@ -47,14 +48,14 @@
</field>
<assembly scope="global" key="assembly-1only" gi="assembly-1only"/>
</assembly>
<group key="groupable-assemblies" gi="groupable-assemblies">
<group key="groupable-assemblies">
<assembly scope="global" gi="assembly-groupable">
<group key="groupable-fields" gi="groupable-fields">
<group key="groupable-fields">
<field scope="global" gi="field-groupable">
<value as-type="string" key="STRVALUE"/>
</field>
</group>
<group key="groupable-assemblies" gi="groupable-assemblies">
<group key="groupable-assemblies">
<assembly scope="global" gi="assembly-groupable"/>
</group>
</assembly>
Expand All @@ -71,22 +72,22 @@
</group>
</assembly>
</group>
<group key="keyed-assemblies" gi="keyed-assemblies" json-key-flag="id">
<group key="keyed-assemblies" group-json="BY_KEY" json-key-flag="id">
<assembly scope="global" gi="assembly-by-key" json-key-flag="id">
<flag as-type="string" scope="global" key="id" gi="id"/>
<group key="keyed-fields" gi="keyed-fields" json-key-flag="id">
<group key="keyed-fields" group-json="BY_KEY" json-key-flag="id">
<field scope="global" gi="field-by-key" json-key-flag="id">
<flag as-type="string" scope="global" key="id" gi="id"/>
<value as-type="string" key="STRVALUE"/>
</field>
</group>
<group key="keyed-assemblies" gi="keyed-assemblies" json-key-flag="id">
<group key="keyed-assemblies" group-json="BY_KEY" json-key-flag="id">
<assembly scope="global" gi="assembly-by-key" json-key-flag="id"/>
</group>
</assembly>
</group>
<group key="everything-recursive" gi="everything-recursive">
<group key="everything-recursive">
<assembly scope="global" gi="EVERYTHING"/>
</group>
</assembly>
</map>
</model>
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
<group-as name="groupable-fields"/>
</field>
<field ref="field-wrappable" max-occurs="unbounded">
<group-as name="wrapped-fields" in-xml="GROUPED"/>
<group-as name="wrapped-fields" in-xml="GROUPED" in-json="ARRAY"/>
</field>
<field ref="field-by-key" max-occurs="unbounded">
<group-as name="keyed-fields" in-json="BY_KEY"/>
Expand Down
2 changes: 1 addition & 1 deletion toolchains/xslt-proto-v04/compose/make-model-map.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<xsl:template match="/METASCHEMA">
<map namespace="{child::namespace ! normalize-space(.) }"
prefix="{child::namespace ! normalize-space(.) }">
prefix="{child::short-name ! normalize-space(.) }">
<xsl:apply-templates select="child::*[exists(root-name)]" mode="build"/>
</map>
</xsl:template>
Expand Down
8 changes: 7 additions & 1 deletion toolchains/xslt-proto-v04/compose/reduce-map.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@

<xsl:mode on-no-match="shallow-copy"/>

<xsl:template match="@group-name | @group-json | @group-xml | @in-xml | @link | @root-name | @use-name"/>
<xsl:template match="@group-name | @group-xml | @in-xml | @link | @root-name | @use-name"/>

<xsl:template match="/map">
<model root-at="{*/@root-name}">
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</model>
</xsl:template>

<xsl:template match="@name">
<xsl:if test="empty(../parent::group)">
Expand Down
5 changes: 4 additions & 1 deletion toolchains/xslt-proto-v04/compose/unfold-model-map.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@

<xsl:mode on-no-match="shallow-copy"/>

<!-- Moved up to new 'group' parent -->
<xsl:template match="@group-json | @group-xml | @group-name"/>

<xsl:template match="*[exists(@group-name)]">
<group name="{@group-name}" in-xml="{ if (@group-xml='GROUPED') then 'SHOWN' else 'HIDDEN' }"
max-occurs="1" min-occurs="{ if (@min-occurs='0') then '0' else '1'}">
<xsl:copy-of select="@json-key-flag"/>
<xsl:copy-of select="@json-key-flag | @group-json"/>
<xsl:next-match/>
</group>
</xsl:template>
Expand Down
181 changes: 181 additions & 0 deletions toolchains/xslt-proto-v04/converter-gen/produce-xml-converter.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
<?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"
xmlns:m="http://csrc.nist.gov/ns/oscal/metaschema/1.0"
xmlns:XSLT="http://csrc.nist.gov/ns/oscal/metaschema/xslt-alias"

xpath-default-namespace="http://csrc.nist.gov/ns/oscal/metaschema/1.0"
exclude-result-prefixes="xs math"
version="3.0"
xmlns="http://csrc.nist.gov/ns/oscal/metaschema/1.0/supermodel">

<!-- Purpose: Produce an XSLT for converting XML valid to a Metaschema model, to its supermodel equivalent. -->
<!-- Input: A Metaschema definition map -->
<!-- Output: An XSLT -->

<xsl:output indent="yes"/>

<xsl:namespace-alias stylesheet-prefix="XSLT" result-prefix="xsl"/>

<xsl:variable name="source-namespace" select="string(/*/@namespace)"/>
<xsl:variable name="source-prefix" select="string(/*/@prefix)"/>

<xsl:template match="/model">
<XSLT:stylesheet version="3.0" xpath-default-namespace="{ $source-namespace }"
exclude-result-prefixes="#all">

<XSLT:strip-space elements="{distinct-values(//assembly/@gi)}"/>

<xsl:comment> METASCHEMA conversion stylesheet supports XML -> METASCHEMA/SUPERMODEL conversion </xsl:comment>
<xsl:text>&#xA;</xsl:text>
<xsl:comment> 888888888888888888888888888888888888888888888888888888888888888888888888888888888 </xsl:comment>
<xsl:text>&#xA;</xsl:text>

<!--<XSLT:character-map name="delimiters">
<!-\- Rewrites Unicode PUA char E0000 to reverse solidus -\->
<!-\-<XSLT:output-character character="&#xE0000;" string="\"/>-\->
</XSLT:character-map>-->

<!-- first we produce templates for (each) of the global definitions.-->
<xsl:for-each-group select="//*[@scope = 'global']"
group-by="string-join((local-name(), @gi), ':')">
<!-- These are all the same so we do only one -->
<xsl:apply-templates select="current-group()[1]" mode="make-template"/>
</xsl:for-each-group>

<!-- next we produce templates for local definitions -->
<xsl:apply-templates select=".//assembly | .//field | .//flag" mode="make-template-for-local"/>

<!--finally, a template for copying prose across, stripping ns -->
<XSLT:template match="*" mode="cast-prose">
<XSLT:element name="{{ local-name() }}" namespace="http://csrc.nist.gov/ns/oscal/metaschema/1.0/supermodel">
<XSLT:copy-of select="@*"/>
<XSLT:apply-templates mode="#current"/>
</XSLT:element>
</XSLT:template>

</XSLT:stylesheet>
</xsl:template>

<xsl:template match="*[@scope='global']" mode="make-template-for-local"/>

<xsl:template match="*" mode="make-template-for-local">
<xsl:apply-templates select="." mode="make-template"/>
</xsl:template>

<!-- no template for implicit wrappers on markup-multiline -->
<xsl:template priority="2" match="field[empty(@gi)][value/@as-type='markup-multiline']" mode="make-template"/>

<xsl:template match="*" mode="make-template">
<xsl:variable name="matching">
<xsl:apply-templates select="." mode="make-xml-match"/>
</xsl:variable>
<xsl:variable name="json-key-flag-name" select="@json-key-flag"/>
<XSLT:template match="{ $matching}">
<xsl:element name="{ local-name() }" namespace="http://csrc.nist.gov/ns/oscal/metaschema/1.0/supermodel">
<xsl:copy-of select="@* except @scope"/>
<xsl:if test="self::field[empty(flag[not(@key=$json-key-flag-name)])]">
<xsl:attribute name="in-json">STRING</xsl:attribute>
</xsl:if>
<xsl:for-each select="parent::model" expand-text="true">
<XSLT:if test=". is /*">
<XSLT:attribute name="namespace">{ $source-namespace }</XSLT:attribute>
<!-- don't need unless we have a requirement to prefix in serialization: <XSLT:attribute name="prefix">{ $source-prefix }</XSLT:attribute>-->
</XSLT:if>
</xsl:for-each>
<xsl:apply-templates select="*" mode="make-pull"/>
</xsl:element>
</XSLT:template>
</xsl:template>

<xsl:template match="flag" mode="make-template">
<xsl:variable name="matching">
<xsl:apply-templates select="." mode="make-xml-match"/>
</xsl:variable>
<XSLT:template match="{ $matching}">
<flag>
<xsl:copy-of select="@* except @scope"/>
<XSLT:value-of select="."/>
</flag>
</XSLT:template>
</xsl:template>

<xsl:template priority="11" match="flag[@scope='global']" mode="make-xml-match make-xml-step">
<xsl:text>@</xsl:text>
<xsl:value-of select="@gi"/>
</xsl:template>

<xsl:template priority="10" match="*[@scope='global']" mode="make-xml-match make-xml-step">
<xsl:value-of select="@gi"/>
</xsl:template>

<xsl:template match="*" mode="make-xml-match">
<xsl:for-each select="ancestor-or-self::*[@gi]">
<xsl:value-of select="if (exists(self::flag)) then '/@' else '/'"/>
<xsl:apply-templates select="." mode="make-xml-step"/>
</xsl:for-each>
</xsl:template>

<xsl:template match="*" mode="make-pull">
<pull who="{local-name()}">
<xsl:copy-of select="@gi | @key"/>
</pull>
</xsl:template>

<xsl:variable name="prose-elements">p | ul | ol | pre | h1 | h2 | h3 | h4 | h5 | h6 | table</xsl:variable>

<!-- A field without a GI is implicit in the XML -->
<xsl:template priority="2" match="field[empty(@gi)][value/@as-type='markup-multiline']" mode="make-pull">
<XSLT:for-each-group select="{ $prose-elements }" group-by="true()">
<field>
<xsl:copy-of select="@gi | @key"/>
<XSLT:apply-templates select="current-group()" mode="cast-prose"/>
</field>
</XSLT:for-each-group>
</xsl:template>

<xsl:template match="flag" mode="make-pull">
<XSLT:apply-templates select="@{@gi}"/>
</xsl:template>

<xsl:template match="field | assembly | group[exists(@gi)]" mode="make-pull">
<XSLT:apply-templates select="{@gi}"/>
</xsl:template>

<xsl:template priority="2" match="group" mode="make-pull">
<xsl:variable name="json-grouping" select="if (exists(@group-json)) then @group-json else 'SINGLETON_OR_ARRAY'"/>
<XSLT:for-each-group select="{ */@gi }" group-by="true()">
<group in-json="{ $json-grouping }">
<xsl:copy-of select="@key"/>
<XSLT:apply-templates select="current-group()"/>
</group>
</XSLT:for-each-group>
</xsl:template>


<!--<xsl:template match="field | assembly" mode="make-pull">
<XSLT:for-each select="{@gi}">
<xsl:element name="{ local-name() }"
namespace="http://csrc.nist.gov/ns/oscal/metaschema/1.0/supermodel">
<xsl:copy-of select="@gi | @key"/>
<xsl:apply-templates mode="#current"/>
</xsl:element>
</XSLT:for-each>
</xsl:template>-->

<xsl:template match="value[@as-type='markup-multiline']" mode="make-pull">
<XSLT:for-each-group select="{ $prose-elements }" group-by="true()">
<XSLT:apply-templates select="current-group()" mode="cast-prose"/>
</XSLT:for-each-group>
</xsl:template>

<xsl:template match="value" mode="make-pull">
<value>
<xsl:copy-of select="@gi | @key | @as-type"/>
<XSLT:value-of select="."/>
</value>
</xsl:template>


</xsl:stylesheet>
Loading

0 comments on commit 67c7ddd

Please sign in to comment.