0
votes

I have a XML and XSL file in client and want to transform it to a HTMLElement so that I can append to my current element

But the result is far from what I expected. Every seems fine except the <td> and <tr> tags is excluded in the HtmlElement result

My XML file

<?xml version="1.0" encoding="UTF-8"?>
<ns1:Courses xmlns:ns1="www.Course.com">
    <ns1:Course xmlns:ns1="www.Course.com">
        <ns1:Id>2153</ns1:Id>
        <ns1:Name>7 bước làm sao tận hưởng một chuyến du lịch nước ngoài với chi phí thấp</ns1:Name>
        <ns1:Author>Hoàng Lê Giang</ns1:Author>
        <ns1:AuthorImageURL>
            d1nzpkv5wwh1xf.cloudfront.net/320/k-57b67d6f60af25054a055b25/20170928-gianghl_2809/gianghl01.jpg
        </ns1:AuthorImageURL>
        <ns1:Rating>0.0</ns1:Rating>
        <ns1:RatingNumber>0</ns1:RatingNumber>
        <ns1:Cost>599000.0</ns1:Cost>
    </ns1:Course>

My XSL file

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="html" encoding="UTF-8" indent="yes" media-type="text/html"/>
    <xsl:template match="/">

        <xsl:for-each select="//*[local-name()='Course']">
            <tr>
                <td class="col1">
                    <div class="course_name">
                        <a href="{*[local-name()='SourceURL']}">
                            <xsl:value-of select="*[local-name()='Name']"/>
                        </a>

                    </div>
                    <div class="course_small_detail">

                        <img class="img_author_small"
                             src="{*[local-name()='AuthorImageURL']}"/>
                        <span class="author_name">
                            <xsl:value-of select="*[local-name()='Author']"/>
                        </span>

                    </div>


                </td>

                <td class="col2">
                    <xsl:value-of select="*[local-name()='Cost']"/>
                </td>
                <td class="col3">
                    <xsl:value-of select="*[local-name()='Rating']"/>
                </td>
            </tr>
        </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

My javascript code that used to transform and append result

var xmlDoc = xmlHttp.responseXML;
            var xslDoc = xslHttp.responseXML;

            xsltProcessor = new XSLTProcessor();
            xsltProcessor.importStylesheet(xslDoc);

            //used to add to html document
            var resultDocument = xsltProcessor.transformToFragment(xmlDoc, document);
            console.log(resultDocument);
            document.getElementById("xmlResult").appendChild(resultDocument);

My html result render

 <table class="table_result">
                    <thead>
                    <tr>
                        <th>header1 </th>

                        <th>header2 </th>
                        <th>header3 </th>
                    </tr>
                    </thead>
                    <tbody id="xmlResult">
                    </tbody>
</table>

I believe this is because of the XSLTProcessor that I use to transform, because I tried to transform it with my IDE's XSLT tool, and the result is perfectly correct

1
Does that problem occur with a particular browser or with all supporting XSLTProcessor? Can you reduce the problem to a minimum and insert it as an executable code snippet? Have you tried to have the XSLT create a complete HTML table and then to use Javascript to replace the existing table with the result fragment from the XSLT execution? - Martin Honnen
I am currently not sure what causes the problem but I guess due to the different ways browsers use XSLT (i.e. Firefox doing node to node transformation, Chrome using libxslt to serialize/parse and perhaps serialize again) trying to create a sequence of tr elements is asking for trouble. - Martin Honnen
I tried with different browsers and the result is still the same sadly :( - Ziggy192
I tried an example jsfiddle.net/bycptmL2/3 and it works in Firefox for me, not in Chrome. As I said, while both have the same API with XSLTProcessor and transformToFragment, I think their implementation approach, not to say, their whole architecture to integrate XSLT in the browser, differs vastly as far as I know, so that whole idea to to to have XSLT return a fragment with HTML tr elements to be inserted into a tbody is troublesome. - Martin Honnen
On the other hand, jsfiddle.net/bycptmL2/4, which only changes the XSLT to output XHTML tr element nodes, works in both Firefox and Chrome for me. Not sure about Edge, doesn't seem to work at all with that fiddle. - Martin Honnen

1 Answers

2
votes

With current versions of Firefox, Chrome and Edge on Windows 10 1803 it works for me to have XSLT return a fragment with XHTML tr elements to then be inserted into the hosting HTML document and a tbody:

var domParser = new DOMParser();

var xmlString = `<root>
  <item>
    <value>foo 1<\/value>
    <value>foo 2<\/value>
    <value>foo 3<\/value>
  <\/item>
  <item>    
    <value>bar 1<\/value>
    <value>bar 2<\/value>
    <value>bar 3<\/value>
  <\/item>
<\/root>`;

var xslString = `<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns="http://www.w3.org/1999/xhtml">
  <xsl:output method="xml" indent="yes"/>
  
  <xsl:template match="item">
    <tr>
      <xsl:apply-templates/>
   <\/tr>
 <\/xsl:template>
 
 <xsl:template match="value">
   <td>
     <xsl:apply-templates/>
   <\/td>
 <\/xsl:template>
 
<\/xsl:stylesheet>`;

var xmlInputDoc = domParser.parseFromString(xmlString, 'application/xml');

var xsltDoc = domParser.parseFromString(xslString, 'application/xml');

var xsltProc = new XSLTProcessor();
xsltProc.importStylesheet(xsltDoc);

var fragment = xsltProc.transformToFragment(xmlInputDoc, document);

console.log(fragment);

var table = document.getElementById('table1');

var tBody = document.getElementById('xmlResult');

tBody.appendChild(fragment);
<table id="table1" class="table_result">
                    <thead>
                    <tr>
                        <th>header1 </th>

                        <th>header2 </th>
                        <th>header3 </th>
                    </tr>
                    </thead>
                    <tbody id="xmlResult">
                    </tbody>
</table>