Reputation: 12423
I have a main.xml which I open in the Safari browser. It is processed just fine by the XSL file indicated at the top.
I have some javascript on the resulting page which should take a second XML file and process it using the given XSL in the href call.
The XSL on the second file, category.xml, seems to work fine (as evidenced by the alert) but when it is inserted as a child to the contentbody div, it does not render as expected.
To show what it should look like, I copied the output of the second XSL process, from the alert dialog, into the originally rendered contentbody div. It looks fine, just like a ul element should produce. When replacing it with the XSL output, it is very wrong.
I would really appreciate some help with this. Why is Safari (Mac OS Lion and iPad mobile Safari) not rendering the inserted HTML output by the XSL executed in Javascript properly? How should I fix this?
Thank you,
Matt.
main.xml
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="main.xslt"?>
<Feed xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/">
<Status>OK</Status>
<Result>
<FeedDTO>
<Id>2286</Id>
<Name>Free to view</Name>
<IconName />
</FeedDTO>
<FeedDTO>
<Id>2320</Id>
<Name>Latest news</Name>
<IconName />
</FeedDTO>
<FeedDTO>
<Id>2249</Id>
<Name>Some reviews</Name>
<IconName />
</FeedDTO>
<FeedDTO>
<Id>2250</Id>
<Name>The wrap</Name>
<IconName />
</FeedDTO>
</Result>
</Feed>
main.xsl
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:msws="http://tempuri.org/"
>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>main</title>
<link href="StyleSheet1.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
function transform(xmlfile,xslfile)
{
var xmlRequest = new XMLHttpRequest();
xmlRequest.open("GET", xmlfile, false);
xmlRequest.send(null);
xml= xmlRequest.responseXML;
var xslRequest = new XMLHttpRequest();
xslRequest.open("GET", xslfile, false);
xslRequest.send(null);
xsl = xslRequest.responseXML;
xsltProcessor = new XSLTProcessor();
xsltProcessor.importStylesheet(xsl);
resultDocument = xsltProcessor.transformToFragment(xml,document);
document.getElementById("contentbody").appendChild(resultDocument);
}
function go(xmlfile,xslfile)
{
var xmlRequest = new XMLHttpRequest();
xmlRequest.open("GET", xmlfile, false);
xmlRequest.send(null);
xml= xmlRequest.responseXML;
var xslRequest = new XMLHttpRequest();
xslRequest.open("GET", xslfile, false);
xslRequest.send(null);
xsl = xslRequest.responseXML;
xsltProcessor=new XSLTProcessor();
xsltProcessor.importStylesheet(xsl);
resultDocument = xsltProcessor.transformToFragment(xml,document);
document.getElementById("contentbody").innerHTML = "";
document.getElementById("contentbody").appendChild(resultDocument);
}
function loadXMLDoc(dname)
{
if (window.XMLHttpRequest)
{
xhttp=new XMLHttpRequest();
}
else
{
xhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xhttp.open("GET",dname,false);
xhttp.send("");
return xhttp.responseXML;
}
function displayResult(xmlfile,xslfile)
{
xml=loadXMLDoc(xmlfile);
xsl=loadXMLDoc(xslfile);
xsltProcessor=new XSLTProcessor();
xsltProcessor.importStylesheet(xsl);
resultDocument = xsltProcessor.transformToFragment(xml,document);
document.getElementById("contentbody").innerHTML = "";
document.getElementById("contentbody").appendChild(resultDocument);
alert(document.getElementById("contentbody").innerHTML);
}
</script>
</head>
<body>
<div id="main">
<div id="menu">
<div id="categorytitle">
Categories
</div>
<ul id="categorybody">
<xsl:for-each select="*/*/msws:FeedDTO">
<xsl:if test="msws:Name != 'Free to view'">
<li id="menuitem">
<xsl:element name="a">
<xsl:attribute name="href">javascript:void(0)</xsl:attribute>
<xsl:attribute name="onclick">
displayResult('category.xml','category.xslt');
</xsl:attribute>
<xsl:value-of select="substring(msws:Name, 1, 100)"/>
</xsl:element>
</li>
</xsl:if>
</xsl:for-each>
</ul>
</div>
<div id="content">
<div id="contenttitle">
Content
</div>
<div id="contentbody"><!-- CONTENT HERE COPIED FROM ALERT TO SHOW WHAT IT SHOULD LOOK LIKE -->
<div xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msws="http://tempuri.org/"><ul id="categorybody"><li id="categoryitem"><a href="javascript:void(0)" onclick="
XsltTransform('article.xml','article.xslt');
">The first title</a></li><li>07 Oct 2011</li><li>A nice long description 1.</li><li id="categoryitem"><a href="javascript:void(0)" onclick="
XsltTransform('article.xml','article.xslt');
">The second title</a></li><li>06 Oct 2011</li><li>A nice long description 2.</li><li id="categoryitem"><a href="javascript:void(0)" onclick="
XsltTransform('article.xml','article.xslt');
">The third title</a></li><li>06 Oct 2011</li><li>A nice long description 3.</li><li id="categoryitem"><a href="javascript:void(0)" onclick="
XsltTransform('article.xml','article.xslt');
">The fourth title</a></li><li>05 Oct 2011</li><li>A nice long description 4.</li><li id="categoryitem"><a href="javascript:void(0)" onclick="
XsltTransform('article.xml','article.xslt');
">The fifth title</a></li><li>04 Oct 2011</li><li>A nice long description 5.</li></ul></div>
</div>
</div>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
content.xml
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="category.xslt"?>
<Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/">
<Status>OK</Status>
<Result>
<ResultItems>
<ArticleLiteDTO>
<Id>2913935</Id>
<Title>The first title</Title>
<Description>A nice long description 1.</Description>
<PublishedDate>2011-10-07T00:00:00</PublishedDate>
<SmallImageUrl />
<LargeImageUrl />
</ArticleLiteDTO>
<ArticleLiteDTO>
<Id>2913226</Id>
<Title>The second title</Title>
<Description>A nice long description 2.</Description>
<PublishedDate>2011-10-06T00:00:00</PublishedDate>
<SmallImageUrl />
<LargeImageUrl />
</ArticleLiteDTO>
<ArticleLiteDTO>
<Id>2913137</Id>
<Title>The third title</Title>
<Description>A nice long description 3.</Description>
<PublishedDate>2011-10-06T00:00:00</PublishedDate>
<SmallImageUrl />
<LargeImageUrl />
</ArticleLiteDTO>
<ArticleLiteDTO>
<Id>2912539</Id>
<Title>The fourth title</Title>
<Description>A nice long description 4.</Description>
<PublishedDate>2011-10-05T00:00:00</PublishedDate>
<SmallImageUrl />
<LargeImageUrl />
</ArticleLiteDTO>
<ArticleLiteDTO>
<Id>2911761</Id>
<Title>The fifth title</Title>
<Description>A nice long description 5.</Description>
<PublishedDate>2011-10-04T00:00:00</PublishedDate>
<SmallImageUrl />
<LargeImageUrl />
</ArticleLiteDTO>
</ResultItems>
</Result>
</Data>
content.xsl
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:msws="http://tempuri.org/"
>
<xsl:template match="/">
<div>
<ul id="categorybody">
<xsl:for-each select="*/*/*/msws:ArticleLiteDTO">
<li id="categoryitem">
<xsl:element name="a">
<xsl:attribute name="href">javascript:void(0)</xsl:attribute>
<xsl:attribute name="onclick">
XsltTransform('article.xml','article.xslt');
</xsl:attribute>
<xsl:value-of select="msws:Title"/>
</xsl:element>
</li>
<li>
<xsl:call-template name="FormatDate">
<xsl:with-param name="DateTimeParam" select="msws:PublishedDate" />
</xsl:call-template>
</li>
<li>
<xsl:value-of select="msws:Description"/>
</li>
</xsl:for-each>
</ul>
</div>
</xsl:template>
<xsl:template name="FormatDate">
<!-- expecting datetime example: 2009-04-20T00:00:00 -->
<xsl:param name="DateTimeParam" />
<!-- reformat date param to be easier to use -->
<xsl:variable name="DateTime">
<xsl:value-of select="substring($DateTimeParam,1,10)"/>
</xsl:variable>
<!-- new date format January 20, 2007 -->
<xsl:variable name="year">
<xsl:value-of select="substring-before($DateTime,'-')" />
</xsl:variable>
<xsl:variable name="mo-temp">
<xsl:value-of select="substring-after($DateTime,'-')" />
</xsl:variable>
<xsl:variable name="mo">
<xsl:value-of select="substring-before($mo-temp,'-')" />
</xsl:variable>
<xsl:variable name="day">
<xsl:value-of select="substring-after($mo-temp,'-')" />
</xsl:variable>
<xsl:if test="(string-length($day) < 2)">
<xsl:value-of select="0"/>
</xsl:if>
<xsl:value-of select="$day"/>
<xsl:value-of select="' '"/>
<xsl:choose>
<xsl:when test="$mo = '1' or $mo = '01'">Jan</xsl:when>
<xsl:when test="$mo = '2' or $mo = '02'">Feb</xsl:when>
<xsl:when test="$mo = '3' or $mo = '03'">Mar</xsl:when>
<xsl:when test="$mo = '4' or $mo = '04'">Apr</xsl:when>
<xsl:when test="$mo = '5' or $mo = '05'">May</xsl:when>
<xsl:when test="$mo = '6' or $mo = '06'">Jun</xsl:when>
<xsl:when test="$mo = '7' or $mo = '07'">Jul</xsl:when>
<xsl:when test="$mo = '8' or $mo = '08'">Aug</xsl:when>
<xsl:when test="$mo = '9' or $mo = '09'">Sep</xsl:when>
<xsl:when test="$mo = '10'">Oct</xsl:when>
<xsl:when test="$mo = '11'">Nov</xsl:when>
<xsl:when test="$mo = '12'">Dec</xsl:when>
</xsl:choose>
<xsl:value-of select="' '"/>
<xsl:value-of select="$year"/>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Views: 2914
Reputation: 82966
OK - what you have is a namespacing problem. This is the output of transforming content.xml with content.xsl (formatted and abbreviated for readability) as a DOM document fragment.
<?xml version="1.0" encoding="UTF-8"?>
<div
xmlns:msws="http://tempuri.org/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ul id="categorybody">
<li id="categoryitem">
<a href="javascript:void(0)" onclick="
XsltTransform('article.xml','article.xslt');
">The first title</a>
</li>
<li>07 Oct 2011</li>
<li>A nice long description 1.</li>
<li id="categoryitem">
... etc ...
</ul>
</div>
The thing to note about this is that this is an XML based DOM fragment - and the elements are in no namespace. So when you add this direct to your DOM (as is done in your question), Safari will not consider the elements to be HTML elements - because it expects those to be in the http://www.w3.org/1999/xhtml
namespace.
When fragment is serialized, it will be converted into the XML above.
When that XML is parsed back using innerHTML, (as is done in your revised working code), the parser will treat the XML as HTML. In accordance with HTML5 parsing practice, the elements will automatically be put in to the http://www.w3.org/1999/xhtml
namespace and will be treated as HTML, so things work as intended.
There's a couple of problems with your solution. The first is that serializing as XML and parsing back as HTML is risky. For example, script elements may get serialized as <script src="..." />
which is OK as XML, but not as HTML.
Second, it requires a serialize/parse cycle that will hurt performance.
Resolving this may be as simple as adding xmlns="http://www.w3.org/1999/xhtml"
as an attribute to the xsl:stylsheet
element of content.xsl
, but I haven't tested this in Safari.
Upvotes: 2
Reputation: 12423
Ok, I don't really understand why this works, so I would really appreciate a description of what is going on here and what was possibly wrong with the original code, but here is a new version of the main.xslt which actually does what it is supposed to.
main.xslt
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:msws="http://tempuri.org/"
>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>main</title>
<link href="StyleSheet1.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
function transform(xmlfile,xslfile)
{
var xmlRequest = new XMLHttpRequest();
xmlRequest.open("GET", xmlfile, false);
xmlRequest.send(null);
xml= xmlRequest.responseXML;
var xslRequest = new XMLHttpRequest();
xslRequest.open("GET", xslfile, false);
xslRequest.send(null);
xsl = xslRequest.responseXML;
xsltProcessor = new XSLTProcessor();
xsltProcessor.importStylesheet(xsl);
resultDocument = xsltProcessor.transformToFragment(xml,document);
document.getElementById("contentbody").appendChild(resultDocument);
}
function go(xmlfile,xslfile)
{
var xmlRequest = new XMLHttpRequest();
xmlRequest.open("GET", xmlfile, false);
xmlRequest.send(null);
xml= xmlRequest.responseXML;
var xslRequest = new XMLHttpRequest();
xslRequest.open("GET", xslfile, false);
xslRequest.send(null);
xsl = xslRequest.responseXML;
xsltProcessor=new XSLTProcessor();
xsltProcessor.importStylesheet(xsl);
resultDocument = xsltProcessor.transformToFragment(xml,document);
document.getElementById("contentbody").innerHTML = "";
document.getElementById("contentbody").appendChild(resultDocument);
}
function loadXMLDoc(dname)
{
xhttp=new XMLHttpRequest();
xhttp.open("GET",dname,false);
xhttp.send("");
return xhttp.responseXML;
}
function displayResult(xmlfile,xslfile)
{
xml=loadXMLDoc(xmlfile);
xsl=loadXMLDoc(xslfile);
xsltProcessor=new XSLTProcessor();
xsltProcessor.importStylesheet(xsl);
var XmlDom = xsltProcessor.transformToDocument(xml);
var serializer = new XMLSerializer();
var output = serializer.serializeToString(XmlDom.documentElement);
//alert(output);
// resultDocument = xsltProcessor.transformToFragment(xml,document);
document.getElementById("contentbody").innerHTML = "";
// document.getElementById("contentbody").appendChild(resultDocument);
document.getElementById("contentbody").innerHTML = output;
// alert(document.getElementById("contentbody").innerHTML);
}
</script>
</head>
<body>
<div id="main">
<div id="menu">
<div id="categorytitle">
Categories
</div>
<ul id="categorybody">
<xsl:for-each select="*/*/msws:FeedDTO">
<xsl:if test="msws:Name != 'Free to view'">
<li id="menuitem">
<xsl:element name="a">
<xsl:attribute name="href">javascript:void(0)</xsl:attribute>
<xsl:attribute name="onclick">
displayResult('category.xml','category.xslt');
</xsl:attribute>
<xsl:value-of select="substring(msws:Name, 1, 100)"/>
</xsl:element>
</li>
</xsl:if>
</xsl:for-each>
</ul>
</div>
<div id="content">
<div id="contenttitle">
Content
</div>
<div id="contentbody">
<!--
<div xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msws="http://tempuri.org/"><ul id="categorybody"><li id="categoryitem"><a href="javascript:void(0)" onclick="
XsltTransform('article.xml','article.xslt');
">The first title</a></li><li>07 Oct 2011</li><li>A nice long description 1.</li><li id="categoryitem"><a href="javascript:void(0)" onclick="
XsltTransform('article.xml','article.xslt');
">The second title</a></li><li>06 Oct 2011</li><li>A nice long description 2.</li><li id="categoryitem"><a href="javascript:void(0)" onclick="
XsltTransform('article.xml','article.xslt');
">The third title</a></li><li>06 Oct 2011</li><li>A nice long description 3.</li><li id="categoryitem"><a href="javascript:void(0)" onclick="
XsltTransform('article.xml','article.xslt');
">The fourth title</a></li><li>05 Oct 2011</li><li>A nice long description 4.</li><li id="categoryitem"><a href="javascript:void(0)" onclick="
XsltTransform('article.xml','article.xslt');
">The fifth title</a></li><li>04 Oct 2011</li><li>A nice long description 5.</li></ul></div>-->
</div>
</div>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0