2

I'm trying to display a XML file with WKWebView. Has anyone got it managed to display it? I've set up a complete sample app (see below). The results were obtained by testing on iOS 9.3 iPhone 4S simulator.

LoadFileUrl()

string targetFilepath = Init("simplexsl.xml");
Init("simple.xsl");

NSUrl url = new NSUrl("file:///" + targetFilepath, false);
NSUrl readAccessUrl = new NSUrl("file:///" + Path.GetDirectoryName(targetFilepath), true);
webview.LoadFileUrl(url, readAccessUrl);

Result: white page

LoadHtmlString()

string targetFilepath = Init("simplexsl.xml");
Init("simple.xsl");

NSData documentData = NSData.FromFile(targetFilepath);

if(documentData != null && documentData.Length > 0)
{
    NSString htmlString = NSString.FromData(documentData, NSStringEncoding.UTF8);
    webview.LoadHtmlString(htmlString, readAccessUrl);
}

Result: content of xml is shown (without tags from xml), but styling is not applied.

NSUrl readAccessUrl = new NSUrl("file:///" + Path.GetDirectoryName(targetFilepath), true);

NSString htmlString = new NSString(File.ReadAllText(targetFilepath));
webview.LoadHtmlString(htmlString, readAccessUrl);

Result: content of xml is shown (without tags from xml), but styling is not applied.

LoadData()

string targetFilepath = Init("simplexsl.xml");
Init("simple.xsl");

NSUrl readAccessUrl = new NSUrl("file:///" + Path.GetDirectoryName(targetFilepath), true);

NSData documentData = NSData.FromFile(targetFilepath);

if(documentData != null && documentData.Length > 0)
{
    webview.LoadData(documentData, "text/xml", "utf-8", readAccessUrl);
}

Result: white page

LoadRequest()

string targetFilepath = Init("simplexsl.xml");
Init("simple.xsl");

NSUrl url = new NSUrl("file:///" + targetFilepath, false);
webview.LoadRequest(new NSUrlRequest(url));

Result: white page

Different paths

var documents = NSFileManager.DefaultManager.GetUrls(NSSearchPathDirectory.LibraryDirectory, NSSearchPathDomain.User) [0].Path;
var caches = Path.Combine (documents, "Caches");

Result: white page

var caches = Path.Combine(System.IO.Path.GetTempPath(), "www");
Directory.CreateDirectory(caches);

Result: white page

Bundle Resource

string folder = NSBundle.MainBundle.BundlePath;
string source = Path.Combine(folder, "simplexsl.xml");
webview.LoadFileUrl(new NSUrl(source,false), new NSUrl(folder, true))

Result: white page

Link

Now I loaded a html with a link in it

<a href="simplexsl.xml">XML Link</a>

Result: html page is loaded, clicking the link leads to a white page, if xsl is commented out in xml then the xml is shown without styling

Online

webview.LoadRequest(new NSUrlRequest(new NSUrl("http://www.w3schools.com/xml/simplexsl.xml")));

Result: WKWebView can show the XML file if you allow it load non https resources.

Without XSL

Comment out the following line in simplexsl.xml

<?xml-stylesheet type="text/xsl" href="simple.xsl" ?>

and using

webview.LoadFileUrl(url, readAccessUrl);

Result: content of xml is shown (without tags from xml), but styling is not applied. So it seems that there is a basepath issue, but only with XSL files?

Displaying a html file, which references a picture relatively, does work, when I use LoadFileUrl(). But with xml files there seems to be a problem. For a short test UIWebView seems to handle that better.

So how is it done correctly?


Basic setup

public override void ViewDidLoad()
{
    base.ViewDidLoad();

    var webview = new WKWebView(View.Bounds, new WKWebViewConfiguration());
    View.AddSubview(webview);

    // code here
}

private string Init(string filename)
{
    string sourceFilepath = Path.Combine(NSBundle.MainBundle.BundlePath, filename);
    var library = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments).Replace("Documents", "Library");
    var caches = Path.Combine(library, "Caches");
    var targetFilepath = Path.Combine(caches, filename);

    if (CopyFile(sourceFilepath, targetFilepath))
        return targetFilepath;

    return string.Empty;
}

private bool CopyFile(string sourceFilepath, string targetFilepath)
{
    if (File.Exists(sourceFilepath))
    {
        File.Copy(sourceFilepath, targetFilepath, true);
        return true;
    }
    return false;
}

targetFilepath is something like /Users/some-user/Library/Developer/CoreSimulator/Devices/8808B80D-D232-4599-B776-139409C9DDB8/data/Containers/Data/Application/BC84CFD0-A805-417C-912F-C2B07834C822/Library/Caches/simplexsl.xml

simplexsl.xml

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="simple.xsl" ?>
<breakfast_menu>
  <food>
    <name>Belgian Waffles</name>
    <price>$5.95</price>
    <description>two of our famous Belgian Waffles with plenty of real maple syrup</description>
    <calories>650</calories>
  </food>
  <food>
    <name>Strawberry Belgian Waffles</name>
    <price>$7.95</price>
    <description>light Belgian waffles covered with strawberries and whipped cream</description>
    <calories>900</calories>
  </food>
  <food>
    <name>Berry-Berry Belgian Waffles</name>
    <price>$8.95</price>
    <description>light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
    <calories>900</calories>
  </food>
  <food>
    <name>French Toast</name>
    <price>$4.50</price>
    <description>thick slices made from our homemade sourdough bread</description>
    <calories>600</calories>
  </food>
  <food>
    <name>Homestyle Breakfast</name>
    <price>$6.95</price>
    <description>two eggs, bacon or sausage, toast, and our ever-popular hash browns</description>
    <calories>950</calories>
  </food>
</breakfast_menu>

simple.xsl

<?xml version="1.0" encoding="UTF-8"?>
<html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE">
    <xsl:for-each select="breakfast_menu/food">
      <div style="background-color:teal;color:white;padding:4px">
        <span style="font-weight:bold">
          <xsl:value-of select="name"/> -
        </span>
        <xsl:value-of select="price"/>
      </div>
      <div style="margin-left:20px;margin-bottom:1em;font-size:10pt">
        <p>
          <xsl:value-of select="description"/>
          <span style="font-style:italic">
            (<xsl:value-of select="calories"/> calories per serving)
          </span>
        </p>
      </div>
    </xsl:for-each>
  </body>
</html>

It would be no problem if you post your solutions in Objective-C or Swift.

testing
  • 17,950
  • 38
  • 208
  • 373

1 Answers1

2

I've the bad feeling, that the XSL transform is not allowed for local files (despite in the same directory) because of security concerns. If I open the file in Chrome I get

Unsafe attempt to load URL file:///C:/some/path/Projects/TestWKWebView/TestWKWebView/Resources/simple.xsl from frame with URL file:///C:/some/path/Projects/TestWKWebView/TestWKWebView/Resources/simplexsl.xml. 'file:' URLs are treated as unique security origins.

Firefox works fine. In Edge I get

XSLT8690: The system cannot locate the object specified.

Very interesting comment from here:

Interesting fact: Safari on Mac (8.0) works just fine with local XSLT, but Safari on iOS (8) simulator (and I suppose on iOS as well) I got the same error like in Chrome "Domains, protocols and ports must match.". But if I'm to implement UIWebView in the app and load XML with XSLT everything works OK.

After some research it seems that there are the following solutions:

  • Use UIWebView
  • Use a local webserver (e.g. look here)
  • Perhaps do the XSLT yourself with the help of libxslt (see here or here, also available as NuGet package)
Community
  • 1
  • 1
testing
  • 17,950
  • 38
  • 208
  • 373