I'm trying to create a Javascript tool that can convert XACML policies for AuthzForce to JSON and back using Saxon-JS. This documentation provides the required XSL stylesheets. Converting from XML to JSON works without a hitch but I'm having issues converting the JSON back to XML.
The transformation function returns a response with all the value data where the keys have been stripped from the SEF file in the "textContent" of the "principalResult".
This is the function I wrote to start the transformation and return an XML string:
function transformJsonToXml(input) {
//Convert JSON object to string
input = JSON.stringify(input);
//Options for SaxonJS transformer
var options = {
stylesheetLocation: jsonToXmlStylesheet,
sourceType: "json",
inJsonFile: input,
destination: "document",
logLevel: "2"
};
//Transformation of JSON to XML
let result = SaxonJS.transform(options);
let policyXml = SaxonJS.serialize(result.principalResult);
//Return the transformation result
return policyXml;
}
This is the start of what I get back in "policyXml" which is just the data from the SEF but without any JSON formatting:
package301SaxonJS 2.6JS2TOP-LEVELtrue2024-04-03T14:59:27.482+01:00xml=~ xsl=~ xacml=urn:oasis:names:tc:xacml:3.0:core:schema:wd-17
This is the XSL file I have converted to SEF using the command xslt3 -t -xsl:stylesheet.xsl -export:stylesheet.sef.json -nogo -relocate:on -ns:##html5
. The resulting SEF file can be found here.
The documentation of SaxonJS https://www.saxonica.com/saxon-js/documentation2/index.html#!api/transform shows the options sourceText
which I think you would want to set to sourceText : input
if you had the JSON as a string and that stylesheet expected the JSON as a string.
I am not sure where you found the option inJsonFile
for SaxonJS, however, it seems to be a global parameter of the stylesheet in https://github.com/authzforce/xacml-json-model/blob/develop/src/test/resources/xacml-policy-json-to-xml.xsl#L30 used with <xsl:apply-templates select="json-to-xml(unparsed-text($inJsonFile))" />
, meaning the JSON is supposed to exist as a text/JSON file on disk to be loaded by the unparsed-text
function.
That stylesheet doesn't take a source input so I wouldn't set one, instead make sure get SaxonJS to read stylesheetParams : { inJsonFile: 'someFile.json' }
in the options.
I see also no use for -ns:##html5
when compiling that stylesheet.
If you don't have a JSON file at all but only a JSON string, then you need to use a different stylesheet doing (make sure you have xmlns:xs="http://www.w3.org/2001/XMLSchema"
declared in the XSLT stylesheet) e.g.
<xsl:param name="jsonData" as="xs:string"/>
<xsl:template name="xsl:initial-template">
<xsl:apply-templates select="json-to-xml($jsonData)" />
</xsl:template>
and set e.g. stylesheetParams : { jsonData: input }
.
As an example:
console.log(SaxonJS.XPath.evaluate(`transform(
map {
'stylesheet-location' : 'https://raw.githubusercontent.com/authzforce/xacml-json-model/develop/src/test/resources/xacml-policy-json-to-xml.xsl',
'stylesheet-params' : map { QName('', 'inJsonFile') : 'https://raw.githubusercontent.com/authzforce/xacml-json-model/develop/src/test/resources/xacml%2Bjson.samples/Policies/valid/driver-access-policy.xacml.json' },
'delivery-format' : 'serialized'
}
)?output`));
<script src="https://martin-honnen.github.io/SaxonJS-2.6/SaxonJS2.js"></script>
Or, if we have the JSON as a string and use a function:
<script src="https://martin-honnen.github.io/SaxonJS-2.6/SaxonJS2.js"></script>
<script type=module>
var jsonInput = await (await fetch('https://raw.githubusercontent.com/authzforce/xacml-json-model/develop/src/test/resources/xacml%2Bjson.samples/Policies/valid/driver-access-policy.xacml.json')).text();
console.log(
SaxonJS.XPath.evaluate(`
transform(
map {
'stylesheet-text' : '<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"><xsl:import href="https://raw.githubusercontent.com/authzforce/xacml-json-model/develop/src/test/resources/xacml-policy-json-to-xml.xsl"/><xsl:param name="jsonData"/><xsl:template name="xsl:initial-template"><xsl:apply-templates select="json-to-xml($jsonData)"/></xsl:template></xsl:stylesheet>',
'stylesheet-params' : map { QName('', 'jsonData') : $jsonInput },
'delivery-format' : 'serialized'
}
)?output`, null, { params : { jsonInput: jsonInput}}));
</script>