iOS14 Safari browser : new XSLTProcessor().importStylesheet(xsl_file)).transformToDocument(newParsedXML) removes the href attribute from the <a> tag

Hello Team,

We are seeing some issues with the XSLT transformation with iOS14 version(starting 14.1 version) and this was working fine in earlier versions.

Issue : When an XSLT transformation is done using transformToDocument, we are observing that the anchor tag has the href attribute removed. Please refer to below example.

Sample usage :
Code Block
new XSLTProcessor().importStylesheet(xsl_file)).transformToDocument(newParsedXML)

Sample line from XSL file :
Code Block
<td><a href="javascript:alert(1)"><xsl:value-of select="catalog/cd/address"/></a></td>


Expected :
Code Block
<a href="javascript:alert(1)">Bangalore</a>


Actual :
Code Block
<a>Bangalore</a>


The UX is broken due to this as the links are no longer clickable with the href attribute being removed.

However, when the href contains the link(as below) - this works as expected.

Sample line from XSL file :
Code Block
<td><a href="https://www.google.com"><xsl:value-of select="catalog/cd/artist"/></a></td>


Expected :
Code Block
<a href="https://www.google.com">ArtistName</a>


Actual :
Code Block
<a href="https://www.google.com">ArtistName</a>


Any help on this would be very much appreciated. Looking forward for a quick response

I have enclosed the sample HTML and the XSL file for reference.

HTML :

Code Block
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Blank Form</title>
<h1>SAMPLE HTML PAGE</h1>
</head>
<body>
<button onclick="doTransform()">Click for XSLT Transformation</button>
<div class="add-info" style="display: none;">
<br>
<h3> Transformed XML Document </h3> : <span id="disp-div"></span>
</div>
<script>
function doTransform() {
//Create the XML
var sampleXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><catalog><cd><title>Test Title</title><artist>CLICK ME!</artist></cd></catalog>";
var parser = new DOMParser();
var newParsedXML = parser.parseFromString(sampleXML, "text/xml");
//Load the XSLT file
var response = getData("../../../assets/xslt/emxSampleXSL.xsl");
var dom = document.implementation.createDocument("", "", null);
// dom.loadXML(response);
var objDOMParser = new DOMParser();
var objDoc = objDOMParser.parseFromString(response, "text/xml");
while (dom.hasChildNodes())
dom.removeChild(dom.lastChild);
for (var i=0; i < objDoc.childNodes.length; i) {
var objImportedNode = dom.importNode(objDoc.childNodes[i], true);
dom.appendChild(objImportedNode);
}
//Create XSLT Processor
var xslProcess = new XSLTProcessor();
xslProcess.importStylesheet(dom);
//Transform the sample XML with the XSLT
var transformedXML = xslProcess.transformToDocument(newParsedXML);
console.log("---transformedXML---> "+transformedXML);
document.getElementsByClassName('add-info')[0].style.display = 'inline';
document.getElementById('disp-div').innerHTML = new XMLSerializer().serializeToString(transformedXML);
}
function getData(sPath, fnCallback){
var objHTTP = new XMLHttpRequest;
objHTTP.open("get", sPath, fnCallback != null);
objHTTP.send(null);
try {
return objHTTP.responseText;
} finally {
objHTTP = null;
}
}
function loadXML(response){
var objDOMParser = new DOMParser();
var objDoc = objDOMParser.parseFromString(response, "text/xml");
while (this.hasChildNodes())
this.removeChild(this.lastChild);
for (var i=0; i < objDoc.childNodes.length; i) {
var objImportedNode = this.importNode(objDoc.childNodes[i], true);
this.appendChild(objImportedNode);
}
}
</script>
</body>
</html>

XSL file :

Code Block
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="link">
<xsl:template match="/">
<html>
<body>
<h2> My Data : </h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>Title</th>
<th>Artist</th>
<th>Address</th>
</tr>
<tr>
<td><xsl:value-of select="catalog/cd/title"/></td>
<td><a href="link"><xsl:value-of select="catalog/cd/artist"/></a></td>
<td><a href="javascript:alert(1)"><xsl:value-of select="catalog/cd/address"/></a></td>
</tr>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>


Answered by mohanmoni07 in 658763022
Hello Team,

Can you please confirm if this is a bug and when the created ticket <rdar://problem/73413312> is expected to be resolved?

Will this fix be available in next iOS version update - say iOS 14.4 ?

Please confirm on this as we are currently blocked with these issues.

Thanks,
Mohan

Looks like a bug. Did you file a Feedback Assistant bug report? If so, please post the FB ID (FBnnnnnnnn) here.
When I try the attached test case in macOS Safari with open source WebKit builds, I keep getting this JavaScript error in the Web Inspector console:

Code Block
[Error] HierarchyRequestError: The operation would yield an incorrect node tree.
appendChild (test.html:31)
doTransform (test.html:31)
onclick (test.html:10)


Fixing this error will make it possible to investigate the bug much quicker.

EDIT: Looks like the Dev Forums might have mangled this link in the XSL:

Code Block
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">


To this:

Code Block
<xsl:stylesheet version="1.0" xmlns:xsl="link">


That made the XSL document invalid.

I am able to reproduce now. Tracked by <rdar://problem/73413312> for any Apple folks reading this.

This behavior changed with this WebKit open source commit: http://trac.webkit.org/changeset/256715

If I'm not mistaken, you can change the behavior using -allowsContentJavaScript in WKWebpagePreferences.h or the javaScriptEnabled @property in WKPreferences.h. (Those are the Objective-C names; I don't know how to convert them to Swift off the top of my head.)

EDIT: Ah, this is for a website and not an app with an embedded WKWebView. I'll check with others to see if this behavior is expected.
Yes, this is on the website. No, i haven't logged any Feedback Assistant bug. Please let me know if any action on my side.

To add more to the above issue. Alternatively, in the xsl we tried to define the <a> as below. But here we see the onclick attribute being removed post the transformation(as below)

Sample XSL line :
Code Block
<td><a href="#" onclick="javascript:alert(1); return false;"><xsl:value-of select="catalog/cd/address"/></a></td>

Expected output :
Code Block
<td><a href="#" onclick="javascript:alert(1); return false;">Bangalore</a></td>


Actual output :
Code Block
<td><a href="#">Bangalore</a></td>


The actual xml namespace we tried with is as below, since it didn't allow me to post as text, i had changed it to link
Code Block
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">


I can see an internal issue has been reported to track this issue <rdar://problem/73413312>
Can you please let us know when can we expect a resolution to this as this was working with iOS versions older than iOS14


Let me know if any inputs needed from my end,

Thanks for your help
Accepted Answer
Hello Team,

Can you please confirm if this is a bug and when the created ticket <rdar://problem/73413312> is expected to be resolved?

Will this fix be available in next iOS version update - say iOS 14.4 ?

Please confirm on this as we are currently blocked with these issues.

Thanks,
Mohan

Hello Team,

Can you please respond on this Bug?

Also please let me know if this ticket is set a CLOSED? I see a Green tick showing next to the question. I might have clicked it by mistake on my last reply. Please confirm on this.

In any case I would create a new ticket as I'm not seeing any response on this for last 3-4 days.
I'm expecting the details on current status of this issue and the timeline when this bug would be resolved


Thanks,


I filed <rdar://problem/73413312> to track the issue internally, but I don't have an update that I can share about it at this time.

I would suggest writing a workaround that re-injects the JavaScript back into the DOM fragment that's returned from the XSLTProcessor. I haven't tried it, but maybe if you change the scheme to "jxvascrxpt:", it won't be removed, then you can run some JavaScript to change the scheme back to "javascript:" after processing.

Or you could try storing the "javascript:" URLs from the XML before it's transformed, do the transform, then re-inject the javascript: URLs back into the transformed DOM fragment (f the order of the items doesn't change).

Sorry for the delayed reply. Without a notification mechanism, I don't have time to follow up on these posts every day. Please give feedback to WWDR that they need to add a "notification" mechanism for people who want to follow issues on this forum. (The old dev forums had this—it was lost in the last major update for WWDC20. You asking WWDR for this will mean a lot more than me asking for it. Also, have every Apple developer you know give the same feedback so WWDR knows it's an issue.)

Thanks for your response.

To add to this, we have also observed that some javascript event handlers like onclick, onresize etc. are also removed post the XSL transformation.

Sample line of code from xsl :
Code Block
<td><input type="button" value="Click me" onclick="javascript:alert(1)"></td>

Expected :
Code Block
<input type="button" value="Click me" onclick="javascript:alert(1)">

Actual :
Code Block
<input type="button" value="Click me">


You can try to reproduce this by just adding this line in the xsl in the shared sample snippet

Please let us know your comments on this issue as well.
We are seeing the same issue. This worked until just recently. Our application is mostly rendered using XSLT and now all of the JavaScript events are stripped out during the transform. What change could have caused this just recently?

XSL:
Code Block xsl
<p class="pseudolink" style="vertical-align:top;font-size:12px" onclick="document.location = '/cgi/evms.opx?cmd=logout'">LOGOUT</p>


Expected Output (HTML):
Code Block html
<p class="pseudolink" style="vertical-align:top;font-size:12px" onclick="document.location = '/cgi/evms.opx?cmd=logout'">LOGOUT</p>


Actual Output (HTML):
Code Block html
<p class="pseudolink" style="vertical-align:top;font-size:12px">LOGOUT</p>

This is happening throughout the entire application. A significant portion of our users are now dead in the water.


iOS14 Safari browser : new XSLTProcessor().importStylesheet(xsl_file)).transformToDocument(newParsedXML) removes the href attribute from the &lt;a&gt; tag
 
 
Q