I want to display a local XML file on a WebView
. The XML file references a local XSL file (in the same folder). But the stylesheet is not applied and the reason for this seems to be security concerns.
If I open the file in the console of Edge I get
XSLT8690: The system cannot locate the object specified.
Is there a possibility to allow the XSL transformation of a local file (e.g. like here)? How can I display a local XML file, which references a stylesheet?
If your XML and XSL file are not in application's assets folder, then setting the WebView.Navigate method or WebView.Source property to the XML file will not work. To solve this issue, we can use XsltProcessor class to transform xml according to the style sheet declaration specified in xslt file first and then using WebView.NavigateToString method to load the transformed HTML content.
For example:
var xmlFile = await ApplicationData.Current.LocalCacheFolder.GetFileAsync("test.xml");
var xsltFile = await ApplicationData.Current.LocalCacheFolder.GetFileAsync("test.xsl");
var doc = await Windows.Data.Xml.Dom.XmlDocument.LoadFromFileAsync(xmlFile);
var xsltDoc = await Windows.Data.Xml.Dom.XmlDocument.LoadFromFileAsync(xsltFile);
// Transform xml according to the style sheet declaration specified in xslt file
var xsltProcessor = new Windows.Data.Xml.Xsl.XsltProcessor(xsltDoc);
var transformedStr = xsltProcessor.TransformToString(doc);
//MyWebView is the WebView control in XAML
MyWebView.NavigateToString(transformedStr);
Update:
I get Error HRESULT E_FAIL has been returned from a call to a COM component. at Windows.Data.Xml.Xsl.XsltProcessor.TransformToString(IXmlNode inputNode).
The problem here is that in your example's XSL file, it is using XSLT document()
function. However for security reasons, execution of the document()
function was prohibited in UWP. So you get the error when executing XsltProcessor.TransformToString
method.
For classic .NET Framework apps, we can set XsltSettings.EnableDocumentFunction Property to enable support for the XSLT document()
function. However there is no such class or property in UWP. You are welcome to submit a request for this feature through UserVoice.
And for your specific XSL file, it only used document()
function in two place:
<xsl:if test="$useexternalcss=1">
<style type="text/css" media="screen">
<xsl:value-of select="document($externalcssname)" />
</style>
</xsl:if>
...
<p class="subtitle_create">
<xsl:text>Angezeigt mit </xsl:text>
<xsl:value-of select="document('')/xsl:stylesheet/@id" />
</p>
For the first place, as it didn't use external css, so the document()
function won't execute. We can ignore it or comment out it for sure. And in the second place, document()
function is used to get the stylesheet
's id
which is "ELGA_Referenzstylesheet_1.04.009.1" and I think this value is a constant. It won't change if the stylesheet didn't change. So I think you can change it like following:
<p class="subtitle_create">
<xsl:text>Angezeigt mit </xsl:text>
<xsl:text>ELGA_Referenzstylesheet_1.04.009.1</xsl:text>
</p>
After this, you can retry with XsltProcessor.TransformToString
method, it should be able to work.
Possible options, which comes to my mind:
- use another browser
- use a local webserver
- put the xml and xsl file onto a webserver and access the URL only (let the webserver make the transformation)
- use XSLT transformation in browser via Javascript (xslt.js, Saxon-CE, Magic XML, Google ajaxslt, Sarissa or even a custom solution)
- use Libxslt library
The disadvantage of the browser method is, that all libraries are outdated and the existing ones do not support all features for the transformation. Implementations can be found here and here. There are also some jQuery wrapper available (see [1], [2] or [3]).
There is also a feature request for the webview.
Copying the xml file to the asset folder, doesn't work. A blank, white page is displayed here. But it works, if you use a file from the asset folder, which you include before compile time.