I am re-writing with Xcode and Swift two applications (DDB Access, SmartHanzi) initially written with Xamarin and C#. Both apps are with separate macOS and iOS versions (storyboard).
In the original version, XSLT 2.0 transformations were applied with C#. With Swift and WKWebView, after carefully reviewing the documentation, I just found:
- XSLT 1.0 transformation for macOS (Swift).
- Nothing at all for iOS.
Some years ago, there seemed to be a possibility with an external C library, but it was also mentioned that at a moment it was no more accepted by the App Store.
Did I miss something in the documentation and how can I apply these XSLT 2.0 transformations (preferrably from an XML string but temporary files would be acceptable)?
WKWebView supports the following APIs on both macOS and iOS:
XSLTProcessor - https://developer.mozilla.org/en-US/docs/Web/API/XSLTProcessor
DOMParser - https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
Here is an example HTML file that includes JavaScript code for performing XSLT transformations to XML data. (Tested in a WKWebView on an iPhone 15 running iOS 17.5.1 (21F90)):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>XSLT Transform Example for iOS</title>
<!-- some style elements added by the XSLT transform -->
<style>
.badword {
border:1px solid rgb(0%,0%,80%);
color:rgb(0%,0%,80%);
font-size:1.2em;
font-weight:bold;
padding-left:3px;
padding-right:3px;
margin-left:2px;
margin-right:2px;
-webkit-border-radius:3px;
}
.customword {
border:1px solid rgb(89%,71%,23%);
color:rgb(80%,36%,12%);
font-size:1.2em;
font-weight:bold;
padding-left:3px;
padding-right:3px;
margin-left:2px;
margin-right:2px;
-webkit-border-radius:3px;
}
</style>
</head>
<body>
<h1>XSLT Transform Example for iOS</h1>
<p>Testing <span class="badword">xslt</span> transforms.</p>
<div id="contents_div">
<p>document startup</p>
</div>
</body>
<script type="text/javascript" language="JavaScript">
/* a simple xslt style sheet
-- note, I have added backslashes at at the end of lines for legibility
as they are stored in this example as JavaScript strings. It is not
necessary to store your XML/XSLT data as strings: you may also
retrieve your XML/XSLT data through some other method. */
var theXSLTText = '\
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">\
<xsl:template match="/">\
<xsl:for-each select="/matches/*">\
<xsl:choose>\
<xsl:when test="name()=\'no\'">\
<span kind="no">\
<xsl:value-of select="."/>\
</span>\
</xsl:when>\
<xsl:when test="name() = \'bad\'">\
<span kind="bad" class="badword">\
<xsl:value-of select="."/>\
</span>\
</xsl:when>\
<xsl:when test="name() = \'custom\'">\
<span kind="custom" class="customword">\
<xsl:value-of select="."/>\
</span>\
</xsl:when>\
</xsl:choose>\
</xsl:for-each>\
</xsl:template>\
</xsl:stylesheet>\
'
/* some xml text to transform */
theXMLText = '\
<matches>\
<no>this</no>\
<bad> is </bad>\
<no>a</no>\
<custom> test </custom>\
<no>of</no>\
<bad> xslt </bad>\
<no>.</no>\
</matches>\
'
/* helper function for adding paragraphs*/
function addPText(containerNode, textToAdd) {
var generatedP = document.createElement("p")
generatedP.appendChild(document.createTextNode(textToAdd))
containerNode.appendChild( generatedP )
}
try {
/* get a reference to the div for output */
var containerNode = document.getElementById('contents_div')
addPText(containerNode, 'starting transform')
/* use a DOMParser to parse the xslt and xml text into DOM trees */
var xml_parser = new DOMParser()
var xslStylesheet = xml_parser.parseFromString( theXSLTText, 'text/xml' )
var xmlDOMTree = xml_parser.parseFromString( theXMLText, 'text/xml' )
/* import the parsed XSLT style sheet into an xslt processor */
xsltProcessor = new XSLTProcessor()
xsltProcessor.importStylesheet( xslStylesheet )
/* transform the xml into a document fragment */
var newDocumentFragment = xsltProcessor.transformToFragment( xmlDOMTree, document )
/* announce start of results */
addPText(containerNode, '- start of transform results -')
/* add the transformed nodes from the xslt result
to the html. Here I destructively remove values, but
you could also perform a traversal or some other algorithm. */
while ( newDocumentFragment.hasChildNodes() ) {
/* pop the first node */
var theNode = newDocumentFragment.firstChild
newDocumentFragment.removeChild(newDocumentFragment.firstChild)
/* add it to the document */
containerNode.appendChild( theNode )
}
/* announce end of results */
addPText(containerNode, '- end of transform results -')
}
catch (e) {
console.log('error ~ ' + e)
var containerNode = document.getElementById('contents_div')
addPText(containerNode, 'error ~ ' + e)
}
</script>
</html>