I am stuck at this. I have an XSLT file that uses an XML file to retrieve data from it.
IN this XSLT file is also a javascript. It's purpose is to create counters to the 'for each' statement in the XSLT.
Now I need to add a feature to the javascript that gets a specific entry from the XML file.
I will paste a part of the xml here so I can explain further.
<ROW>
<Date>03-12-2013</Date>
<School>SvR</School>
<Locale>B1.04</Locale>
<Class>1236VUGK16</Class>
<Time>09:00-16:00</Time>
</ROW>
I need to get the data from "Date". But I do not know how to load an xml file in javascript to achieve this. I've found some html codes that tell me to xmlDoc.load will do this, but it does not. It will give me a syntax error. Is this because it is in XSLT? How can I achieve what I want?
you need 4 things
data.xml -> XML file
Openxml.js -> contains funciton to open Javascript
filejs.js -> contains function to read/write and others things with data.
index.html -> show information
part 1, your xml file:
<?xml version="1.0" encoding="UTF-8"?>
<events>
<ROW>
<Date>03-12-2013</Date>
<School>SvR</School>
<Locale>B1.04</Locale>
<Class>1236VUGK16</Class>
<Time>09:00-16:00</Time>
</ROW>
</events>
part 2:
unction OpenFile(fichXML)
{
var xmlDoc=undefined;
try
{
if (document.all) //IE
{
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
}
else //firefox
{
xmlDoc = document.implementation.createDocument("","",null);
}
xmlDoc.async=false;
xmlDoc.load(fichXML);
}
catch(e)
{
try { //otros safari, chrome
var xmlhttp = new window.XMLHttpRequest();
xmlhttp.open("GET",fichXML,false);
xmlhttp.send(null);
xmlDoc = xmlhttp.responseXML.documentElement;
return xmlDoc;
}
catch (e)
{
return undefined;
}
}
return xmlDoc;
}
part 3:
function Event(date)
{
this.date = date;
}
//funciton to charge XMLElements
function ChargeXMLElements()
{
try
{
xmlDoc=OpenFile("data.xml");
eventosXML=xmlDoc.getElementsByTagName('ROW');
if (eventosXML.length>0)
{
eventos=new Array(); //clase con los datos cargados
}
for(var i=0; i< eventosXML.length; i++)
{
xmlEvento=eventosXML[i];
fecha=xmlEvento.getElementsByTagName("DATE")[0].firstChild.nodeValue;
evento = new Evento(fecha);
eventos.push(evento);
}
return eventos;
}
catch(e)
{
alert("Error on the load data");
}
}
//show information take on previously function, and show on a table (with only 1 column)
function showinformation()
{
var tr;
var td;
var tabla;
var l=0;
ev= CargarXMLEventos();
auxUnEven=ev.pop();
tabla=document.getElementById("datos");
while (auxUnEven!=undefined)
{
tr=tabla.insertRow(l);
//creamos las columnas de la tabla
td=tr.insertCell(0);
td.innerHTML=auxUnEven.date;
/*td=tr.insertCell(1);
td.innerHTML=auxUnEven.hora;
td=tr.insertCell(2);
td.innerHTML=auxUnEven.comentario; */ //if you need more columns
l++;
auxUnEven=ev.pop();
}
if (l==0)
{
tabla=document.getElementById("datos");
tr=tabla.insertRow(l);
td=tr.insertCell(0);
td.innerHTML=" dont have events ";
}
}
part 4:
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>example XML</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="filejs.js"></script>
<script type="text/javascript" src="Openxml.js"></script>
</head>
<body>
<table id="datos">
<script type="text/javascript">
showinformation();
</script>
</table>
</body>
</html>
i think that is functional but i don't know. I see the information here: http://elcaminillo.wordpress.com/2012/01/15/leer-xml-en-javascript/ (spanish, sorry)
Related
I am trying to understand CORS configuration with vert.x. I found an example at this github repository under the CORS section. When i tried it only POST example seemed to work (preflight.html). Since I also need to use GET (nopreflight.html) in one of my projects, I have tried to modify the example obtaining poor results. This is what i have right now:
Server.java
package io.vertx.example.web.cors;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.MultiMap;
import io.vertx.core.http.HttpMethod;
import io.vertx.example.util.Runner;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.CorsHandler;
import io.vertx.ext.web.handler.StaticHandler;
import java.util.Map;
/*
* #author Paulo Lopes
*/
public class Server extends AbstractVerticle {
// Convenience method so you can run it in your IDE
public static void main(String[] args) {
Runner.runExample(Server.class);
}
#Override
public void start() throws Exception {
Router router = Router.router(vertx);
router.route().handler(CorsHandler.create("*")
.allowedMethod(HttpMethod.GET)
.allowedMethod(HttpMethod.POST)
.allowedMethod(HttpMethod.OPTIONS)
.allowedHeader("Access-Control-Request-Method")
.allowedHeader("Access-Control-Allow-Credentials")
.allowedHeader("Access-Control-Allow-Origin")
.allowedHeader("Access-Control-Allow-Headers")
.allowedHeader("X-PINGARUNER")
.allowedHeader("Content-Type"));
router.get("/access-control-with-get").handler(ctx -> {
ctx.response().setChunked(true);
MultiMap headers = ctx.request().headers();
/*for (String key : headers.names()) {
ctx.response().write(key);
ctx.response().write(headers.get(key));
ctx.response().write("\n");
}*/
ctx.response().write("response ");
ctx.response().end();
});
router.post("/access-control-with-post-preflight").handler(ctx -> { ctx.response().setChunked(true);
MultiMap headers = ctx.request().headers();
/*for (String key : headers.names()) {
ctx.response().write(key);
ctx.response().write(headers.get(key));
ctx.response().write("\n");
}*/
ctx.response().write("response ");
ctx.response().end();
});
// Serve the static resources
router.route().handler(StaticHandler.create());
vertx.createHttpServer()
.requestHandler(router::accept)
.listen(8080);
}
}
nopreflight.html
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Simple use of Cross-Site XMLHttpRequest (Using Access Control)</title>
<script type="text/javascript">
//<![CDATA[
var invocation = new XMLHttpRequest();
var url = 'http://localhost:8080/access-control-with-get/';
var invocationHistoryText;
var body = '<?xml version="1.0"?><person><name>Arun</name></person>';
function callOtherDomain(){
if(invocation)
{
invocation.open('GET', url, true);
//invocation.setRequestHeader('X-PINGARUNER', 'pingpong');
invocation.setRequestHeader('Content-Type', 'application/xml');
invocation.onreadystatechange = handler;
invocation.send();
}
else
{
invocationHistoryText = "No Invocation TookPlace At All";
var textNode = document.createTextNode(invocationHistoryText);
var textDiv = document.getElementById("textDiv");
textDiv.appendChild(textNode);
}
}
function handler()
{
if (invocation.readyState == 4)
{
if (invocation.status == 200)
{
var response = invocation.responseXML;
//var invocationHistory = response.getElementsByTagName('invocationHistory').item(0).firstChild.data;
invocationHistoryText = document.createTextNode(response);
var textDiv = document.getElementById("textDiv");
textDiv.appendChild(invocationHistoryText);
}
else
alert("Invocation Errors Occured " + invocation.readyState + " and the status is " + invocation.status);
}
else
console.log("currently the application is at " + invocation.readyState);
}
//]]>
</script>
</head>
<body>
<form id="controlsToInvoke" action="">
<p>
<input type="button" value="Click to Invoke Another Site" onclick="callOtherDomain()" />
</p>
</form>
<p id="intro">
This page basically makes invocations to another domain using cross-site XMLHttpRequest mitigated by Access Control. This is the simple scenario that is <em>NOT</em> preflighted, and the invocation to a resource on another domain takes place using a simple HTTP GET.
</p>
<div id="textDiv">
This XHTML document invokes another resource using cross-site XHR.
</div>
</body>
</html>
preflight.html
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Simple use of Cross-Site XMLHttpRequest (Using Access Control)</title>
<script type="text/javascript">
//<![CDATA[
var invocation = new XMLHttpRequest();
var url = 'http://localhost:8080/access-control-with-post-preflight/';
var invocationHistoryText;
var body = '<?xml version="1.0"?><person><name>Arun</name></person>';
function callOtherDomain(){
if(invocation)
{
invocation.open('POST', url, true);
invocation.setRequestHeader('X-PINGARUNER', 'pingpong');
invocation.setRequestHeader('Content-Type', 'application/xml');
invocation.onreadystatechange = handler;
invocation.send();
}
else
{
invocationHistoryText = "No Invocation TookPlace At All";
var textNode = document.createTextNode(invocationHistoryText);
var textDiv = document.getElementById("textDiv");
textDiv.appendChild(textNode);
}
}
function handler()
{
if (invocation.readyState == 4)
{
if (invocation.status == 200)
{
var response = invocation.responseText;
//var invocationHistory = response.getElementsByTagName('invocationHistory').item(0).firstChild.data;
invocationHistoryText = document.createTextNode(response);
var textDiv = document.getElementById("textDiv");
textDiv.appendChild(invocationHistoryText);
}
else
{
alert("Invocation Errors Occured " + invocation.readyState + " and the status is " + invocation.status);
}
}
else
{
console.log("currently the application is at " + invocation.readyState);
}
}
//]]>
</script>
</head>
<body>
<form id="controlsToInvoke" action="">
<p>
<input type="button" value="Click to Invoke Another Site" onclick="callOtherDomain()" />
</p>
</form>
<p id="intro">
This page POSTs XML data to another domain using cross-site XMLHttpRequest mitigated by Access Control. This is the preflight scenario and the invocation to a resource on another domain takes place using first an OPTIONS request, then an actual POST request.
</p>
<div id="textDiv">
This XHTML document POSTs to another resource using cross-site XHR. If you get a response back, the content of that response should reflect what you POSTed.
</div>
</body>
</html>
EDIT:
Thanks to a suggestion I modified Server.java code to make it clearer and I understood that the problem was the hanlder function in nopreflight.html file. I solved the problem as follows:
EDITED Server.java
public class Server extends AbstractVerticle {
// Convenience method so you can run it in your IDE
public static void main(String[] args) {
Runner.runExample(Server.class);
}
#Override
public void start() throws Exception {
Router router = Router.router(vertx);
Set<String> allowedHeaders = new HashSet<>();
allowedHeaders.add("x-requested-with");
allowedHeaders.add("Access-Control-Allow-Origin");
allowedHeaders.add("origin");
allowedHeaders.add("Content-Type");
allowedHeaders.add("accept");
allowedHeaders.add("X-PINGARUNER");
Set<HttpMethod> allowedMethods = new HashSet<>();
allowedMethods.add(HttpMethod.GET);
allowedMethods.add(HttpMethod.POST);
allowedMethods.add(HttpMethod.DELETE);
allowedMethods.add(HttpMethod.PATCH);
allowedMethods.add(HttpMethod.OPTIONS);
allowedMethods.add(HttpMethod.PUT);
router.route().handler(CorsHandler.create("*")
.allowedHeaders(allowedHeaders)
.allowedMethods(allowedMethods));
router.get("/access-control-with-get").handler(ctx -> {
HttpServerResponse httpServerResponse = ctx.response();
httpServerResponse.putHeader("content-type", "text/html").end("<h1>Success</h1>");
});
EDITED nopreflight.html
<script type="text/javascript">
var xhttp = new XMLHttpRequest();
var url = 'http://localhost:8080/access-control-with-get/';
var invocationHistoryText;
function callOtherDomain() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("textDiv").appendChild(document.createTextNode(xhttp.responseText));
}
};
xhttp.open("GET", url, true);
xhttp.send();
}
</script>
CorsHandler.create("*") will not work.
You will need to provide a regex String on CorsHandler.create("Regex String Here"). That Regex String will need to be a valid Java regex that will work on Pattern.compile("Regex String Here"). So if you want to allow any protocol:host:port, aka "*", through CORS handling you can use.
router.route().handler(CorsHandler.create(".*."); //note the "." surrounding "*"
If you want a fine-grained control of allowed protocol:host:port, you can be creative with the Regex String. For example, to set CORS handling for either http:// or https:// from localhost and any port:
router.route().handler(CorsHandler.create("((http:\\/\\/)|(https:\\/\\/))localhost:\\d+");
You can also use one handler to allow a whitelist of origins, example:
router.route().handler(CorsHandler.create("http:\\/\\/localhost:8080|https:\\/\\/128.32.24.45:\\d+|http:\\/\\/121.0.4.3:8080"));
This seems to be working fine for us
Router router = Router.router(vertx);
Set<String> allowedHeaders = new HashSet<>();
allowedHeaders.add("x-requested-with");
allowedHeaders.add("Access-Control-Allow-Origin");
allowedHeaders.add("origin");
allowedHeaders.add("Content-Type");
allowedHeaders.add("accept");
Set<HttpMethod> allowedMethods = new HashSet<>();
allowedMethods.add(HttpMethod.GET);
allowedMethods.add(HttpMethod.POST);
allowedMethods.add(HttpMethod.DELETE);
allowedMethods.add(HttpMethod.PATCH);
allowedMethods.add(HttpMethod.OPTIONS);
allowedMethods.add(HttpMethod.PUT);
router.route().handler(CorsHandler.create("*")
.allowedHeaders(allowedHeaders)
.allowedMethods(allowedMethods));
router.get("/").handler(context1 -> {
HttpServerResponse httpServerResponse = context1.response();
httpServerResponse.putHeader("content-type", "text/html").end("<h1>Success</h1>");
});
after this if you create httpserver, it should work fine.
I am reading an XML file using JavaScript, and this part works as I am getting the data. Here is the XML file:
<bookstore>
<book category="romance">
<title lang="en">Everyday Italian</title>
<author>Giada</author>
<year>2005</year>
<price>30,00</price>
</book>
<book category="cooking">
<title lang="en">Cook Book</title>
<author>Manado</author>
<year>2012</year>
<price>44,00</price>
</book>
<book category="drama">
<title lang="en">Intrigue</title>
<author>L'amion</author>
<year>2002</year>
<price>29,99</price>
</book>
</bookstore>
Now I use JavaScript to display that data in a table. Also, I added two <input> buttons that each have an onclick attribute to call a specific function. One button calls the change() and the other calls remove().
Here is the code for the HTML page and JavaScript:
<html>
<head>
<title>Index</title>
<script type="text/javascript">
function loadXMLDoc(dname) {
if(window.XMLHttpRequest) {
xhttp = new XMLHttpRequest();
} else { // for IE 5/6
xhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xhttp.open("GET", dname, false);
xhttp.send();
return xhttp.responseXML;
}
// function to print all book titles
function printTitles() {
var xmlDoc = loadXMLDoc('bookstore.xml');
var elements = xmlDoc.getElementsByTagName('title')
document.write('<table border="1"><tr><th>Title</th></tr>');
for(i = 0; i < elements.length; i++) {
document.write("<tr>");
document.write(
"<td>" + elements[i].childNodes[0].nodeValue + "</td>");
document.write("</tr>")
}
document.write("</table>");
}
// function to change the first book title
function change(text) {
var xmlDoc = loadXMLDoc('bookstore.xml');
var elements = xmlDoc.getElementsByTagName('title');
var title = elements[0].childNodes[0];
title.nodeValue = text;
printTitles(elements);
}
// function to remove the first book
function remove(node) {
var xmlDoc = loadXMLDoc('bookstore.xml');
var rem = xmlDoc.getElementsByTagName(node)[0];
xmlDoc.documentElement.removeChild(rem);
printTitles(elements);
}
printTitles();
</script>
</head>
<body>
<input type="button" value="change" onclick="change('WORKS')"/>
<input type="button" value="remove" onclick="remove('book')"/>
</body>
</html>
When I click the change button, both buttons disappear.
When I click the remove button, only remove button disappears.
Here are all 3 states of my page (I cannot upload a photo because I don't have the rep):
http://postimg.org/image/5lrwf7rcz/
Now, I already searched for an answer and this question or this question answers didn't help me. I couldn't find a missing closing tag and returning false doesn't change anything.
UPDATE: I ran the debugger on Chrome and when I click the remove button, the remove() function never gets called but when I click the change button, the change() function does get called.
I found a solution so I though I might post it here in case somebody needs it.
First of all, I was missing a semicolon inside the printTitles() at document.write("</tr>") but that wasn't the main reason behind the program not working.
After taking #Teemu's advice on functions createElement, createTextNode, appendChild and reviewing other helpful comments, I changed the code a lot. I used the mentioned functions and added the window.onload check to make sure I can edit the body after the page loads.
XML file stays the same and here is my HTML file with JavaScript:
<html>
<head>
<title>Index</title>
<script type="text/javascript">
window.onload = function() {
// function that loads an XML file through an HTTP request
function loadXMLDoc(dname) {
if(window.XMLHttpRequest) {
xhttp = new XMLHttpRequest();
} else { // for IE 5/6
xhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xhttp.open("GET", dname, false);
xhttp.send();
return xhttp.responseXML;
}
var xmlDoc = loadXMLDoc('bookstore.xml'); // holds the loaded XML file
// builds a string from xml elements containing the HTML code for the body
function buildBody(elements) {
var body = '<table border="1"><tr><th>Title</th></tr>';
for(i = 0; i < elements.length; i++) {
body += "<tr>";
body +=
"<td id='" + i +"'>" + elements[i].childNodes[0].nodeValue + "</td>";
body += "</tr>";
}
body += "</table>";
return body;
}
// prints the input buttons
function printInputs(elements) {
document.body.innerHTML = buildBody(elements);
// button change
var inputChange = document.createElement('input');
inputChange.setAttribute('type', 'button');
inputChange.setAttribute('value', 'Change first title');
inputChange.onclick = function change() { // on click function for the button
document.getElementById(0).innerHTML = 'WORKS';
}
document.body.appendChild(inputChange); // add button to the body
// button remove
var inputRemove = document.createElement('input');
inputRemove.setAttribute('type', 'button');
inputRemove.setAttribute('value', 'Remove first title');
inputRemove.onclick = function remove() { // on click function for the button
document.getElementById(0).innerHTML = '';
}
document.body.appendChild(inputRemove); // add button to the body
}
function printTitles() {
var xmlDoc = loadXMLDoc('bookstore.xml');
var elements = xmlDoc.getElementsByTagName('title');
printInputs(elements);
}
printTitles();
}
</script>
</head>
<body>
</body>
</html>
I am using html5 and javascript. I want to read the Excel file which is chosen by the user from the directory (using a file dialog) but all I know is to read an excel file by the given path:
function readdata(y,x) {
try {
var excel = new ActiveXObject("Excel.Application");
excel.Visible = false;
var excel_file = excel.Workbooks.Open("D:\\Test.xls");
// alert(excel_file.worksheets.count);
var excel_sheet = excel_file.Worksheets("Sheet1");
var data = excel_sheet.Cells(x, y).Value;
//alert(data);
drawWithexcelValue(data);
}
catch (ex) {
alert(ex);
}
return data;
}
This is what I have to read the excel file. Can any one help me to read a file by directory, or without giving the path of the file. I would also like to know how to show output from that.
Thanx in advance
Try the following code, it is a bit of a hack and it seems to work with IE7. However, it will not work with other browsers because they will not show the file path. Other browsers will also never be able to show the ActiveXObject (Excel).
<!DOCTYPE html>
<html>
<head>
<body>
<div id="divHidden" style="visibility: hidden; width: 0px; height: 0px">
<input type=file id="fileInput">
</div>
<input type=button value="click here to get a file" onclick="readdata(1,1);">
<script language=javascript>
function readdata(y,x) {
// Use the <input type='file'...> object to get a filename without showing the object.
document.all["fileInput"].click();
var fileName = document.all["fileInput"].value;
try {
var excel = new ActiveXObject("Excel.Application");
excel.Visible = false;
var excel_file = excel.Workbooks.Open(fileName);
var excel_sheet = excel_file.Worksheets("Sheet1");
// var data = excel_sheet.Cells(x, y).Value;
var data;
for (; excel_sheet.Cells(x, y).Value.length > 0; x++){
data[i][0] = excel_sheet.Cells(x, y).Value;
data[i][1] = excel_sheet.Cells(x, y+1).Value;
}
drawWithexcelValue(data);
}
catch (ex) {
alert(ex);
}
// This will show the data.
alert(data);
}
</script>
</body>
</html>
I need to save the data offline, so I save the data as XML. I don't know how to get the XML object with JavaScript.
<xml id=xmlData>
<data>
<tb1>
<id>1</id>
<name>1</name>
</tb1>
<tb1>
<id>2</id>
<name>2</name>
</tb1>
</data>
</xml>
<html id="MainForm">
<head id="Head1">
</head>
<body>
<script type="text/javascript">
var xmlDoc;
// code for IE
if (window.ActiveXObject)
{
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
}
// code for Mozilla, Firefox, Opera, etc.
else if (document.implementation.createDocument)
{
xmlDoc=document.implementation.createDocument("","",null);
}
else
{
alert('Your browser cannot handle this script');
}
xmlDoc.async=false;
xmlDoc.load("");//how can i get the xml?
var x=xmlDoc.documentElement.childNodes;
for (var i=0;i<x.length;i++)
{
if (x[i].nodeType==1)
{
//Process only element (nodeType 1) nodes
document.write(x[i].nodeName + ": ");
document.write(x[i].childNodes[0].nodeValue);
document.write("<br />");
}
}
</script>
</body>
</html>
Try this:
var txt='<xml id=xmlData><data><tb1><id>1</id> <name>1</name></tb1><tb1><id>2</id><name>2</name></tb1></data></xml>';
if (window.DOMParser)
{
parser=new DOMParser();
xmlDoc=parser.parseFromString(txt,"text/xml");
}
else // Internet Explorer
{
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async=false;
xmlDoc.loadXML(txt);
}
var x=xmlDoc.documentElement.childNodes;
for (var i=0;i<x.length;i++)
{
if (x[i].nodeType==1)
{
//Process only element (nodeType 1) nodes
console.log(x[i].nodeName + ": ");
console.log(x[i].childNodes[0].nodeValue);
console.log("<br />");
}
}
Fiddle: http://jsfiddle.net/hB5E9/
I use a local variable in the document to do this. If you can get the XML as a string property of an object then this might be useful -
I have a somewhat similar usage in my application. I read an "XML" column from the SQL Azure DB through a service call and I get this XML data as a "string" property of the service return object.
Here is what I am doing to read that :
_LocalVariable= XMLFromString(DataObject.Filter);
$.each($(_LocalVariable).find("Filter"),
function (index,filterDataItem) {
$filterDataItem =$(filterDataItem);
var tFilterType =$filterDataItem.find("FilterType").attr("class");
var tOperator = $filterDataItem.find("Operator").attr("class");
var tValue = $filterDataItem.find("Value").text();
// Do more operations
});
//--------------------------------------------------------------------------------
//Parse XML from String
//--------------------------------------------------------------------------------
function XMLFromString(pXMLString) {
if (!pXMLString)
pXMLString = "<FilterRule></FilterRule>";
if (window.ActiveXObject) {
var oXML = new ActiveXObject("Microsoft.XMLDOM");
oXML.loadXML(pXMLString);
return oXML;
} else {
return (new DOMParser()).parseFromString(pXMLString, "text/xml");
}
}
Where my XML in the database is something like this -
<FilterRule>
<Filter id="1">
<FilterType id="AB11">Ranking</FilterType>
<Operator id="1">Equal To</Operator>
<Value>1</Value>
</Filter>
<Filter id="2">
<FilterType id="AB22">Segment</FilterType>
<Operator id="1">Equal To</Operator>
<Value>2</Value>
</Filter>
<Logic>Or</Logic>
</FilterRule>
I have the following code that applies a XSLT style
Test.Xml.xslTransform = function(xml, xsl) {
try {
// code for IE
if (window.ActiveXObject) {
ex = xml.transformNode(xsl);
return ex;
}
// code for Mozilla, Firefox, Opera, etc.
else if (document.implementation && document.implementation.createDocument) {
xsltProcessor = new XSLTProcessor();
xsltProcessor.importStylesheet(xsl);
resultDocument = xsltProcessor.transformToFragment(xml, document);
return resultDocument;
}
} catch (exception) {
if (typeof (exception) == "object") {
if (exception.message) {
alert(exception.message);
}
} else {
alert(exception);
}
}
The code is working in IE and firefox but not in Chrome and Safari. Any ideas why?
Update
ResultDocument = xsltProcessor.transformToFragment(xml, document);
The line above is returning null. No error is being thrown.
Update
The code is not working as the xslt file contains xsl:include. Need to find a way to get the include working I will paste progress here
Update
It has been recomended that I use the http://plugins.jquery.com/project/Transform/ plugin. I am trying to use the client side libary as the example of include works here (http://daersystems.com/jquery/transform/).
The code works in IE but still not in chrome.
Test.Xml.xslTransform = function(xml, xsl) {
try {
$("body").append("<div id='test' style='display:none;'></div>");
var a = $("#test").transform({ xmlobj: xml, xslobj: xsl });
return a.html();
}
catch (exception) {
if (typeof (exception) == "object") {
if (exception.message) {
alert(exception.message);
}
} else {
alert(exception);
}
}
}
xml and xsl are both objects being passed in.
Update
I tried changing the XSL file to being something very simple with no include and Chrome is still not applying the stylesheet and IE is. The XSL that is being brought in as an object is:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:rs="urn:schemas-microsoft-com:rowset"
xmlns:z="#RowsetSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:spsoap="http://schemas.microsoft.com/sharepoint/soap/"
>
<xsl:output method="html"/>
<xsl:template match="/">
<h1>test</h1>
</xsl:template>
</xsl:stylesheet>
Update
The end result that I want is for the xsl to be applied to the xml file. The xsl file has in it includes. I want the trasnfer to happen on the client ideally.
Updated
Rupert could you update the question with the xml and how you're calling Test.Xml.xslTransform ?
I got the xml using ie8
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><SearchListItemsResponse xmlns="http://schemas.microsoft.com/sharepoint/soap/"><SearchListItemsResult><listitems xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
<rs:data ItemCount="1">
<z:row ows_Title="Test" ows_FirstName="Test 4" ows_UniqueId="74;#{1A16CF3E-524D-4DEF-BE36-68A964CC24DF}" ows_FSObjType="74;#0" ows_MetaInfo="74;#" ows_ID="74" ows_owshiddenversion="10" ows_Created="2009-12-29 12:21:01" ows_FileRef="74;#Lists/My List Name/74_.000" ReadOnly="False" VerificationRequired="0"/>
</rs:data>
</listitems></SearchListItemsResult></SearchListItemsResponse></soap:Body></soap:Envelope>
The code is being called as follows:
xsl = Test.Xml.loadXMLDoc("/_layouts/xsl/xsl.xslt");
var doc = Test.Xml.xslTransform(xData.responseXML, xsl);
xData is the xml returned by a web service.
If your XSLT is using xsl:include you might receive weird unexplainable errors but always with the same end result: your transformation failing.
See this chromium bug report and please support it!
http://code.google.com/p/chromium/issues/detail?id=8441
The bug is actually in webkit though. For more info here's another link which goes into more detail why it doesn't work.
The only way around this is to pre-process the stylesheet so that it injects the included stylesheets. Which is what a crossbrowser XSLT library like Sarissa will do for you automatically.
If your looking for jQuery solution:
http://plugins.jquery.com/project/Transform/ is a cross browser XSL plug-in. I've succesfully used this to get xsl:include working in the past without much hassle. You don't have to rewrite your xsl's this plugin will pre-process them for you. Definitely worth looking at as it's more lightweight then Sarissa.
UPDATE:
<html>
<head>
<script language="javascript" src="jquery-1.3.2.min.js"></script>
<script language="javascript" src="jquery.transform.js"></script>
<script type="text/javascript">
function loadXML(file)
{
var xmlDoc = null;
try //Internet Explorer
{
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async=false;
xmlDoc.load(file);
}
catch(e)
{
try //Firefox, Mozilla, Opera, etc.
{
xmlDoc=document.implementation.createDocument("","",null);
xmlDoc.async=false;
xmlDoc.load(file);
}
catch(e)
{
try //Google Chrome
{
var xmlhttp = new window.XMLHttpRequest();
xmlhttp.open("GET",file,false);
xmlhttp.send(null);
xmlDoc = xmlhttp.responseXML.documentElement;
}
catch(e)
{
error=e.message;
}
}
}
return xmlDoc;
}
function xslTransform(xmlObject, xslObject)
{
try
{
$("body").append("<div id='test'></div>");
var a = $("#test").transform({ xmlobj: xmlObject, xslobj: xslObject });
}
catch (exception)
{
if (typeof (exception) == "object" && exception.message)
alert(exception.message);
else alert(exception);
}
}
var xmlObject = loadXML("input.xml");
var xslObject = loadXML("transform.xsl");
$(document).ready(function()
{
xslTransform(xmlObject, xslObject);
});
</script>
</head>
<body>
</body>
</html>
This test html page works both in Chrome/FireFox/IE.
input.xml is just a simple xml file containing <root />
transform.xsl is the stripped down xsl you posted.
EDIT
It does however seem the $.transform has problems importing stylesheets from included files:
Here's how to fix this:
Locate
var safariimportincludefix = function(xObj,rootConfig) {
in jquery.transform.js and replace the entire function with this:
var safariimportincludefix = function(xObj,rootConfig) {
var vals = $.merge($.makeArray(xObj.getElementsByTagName("import")),$.makeArray(xObj.getElementsByTagName("include")));
for(var x=0;x<vals.length;x++) {
var node = vals[x];
$.ajax({
passData : { node : node, xObj : xObj, rootConfig : rootConfig},
dataType : "xml",
async : false,
url : replaceref(node.getAttribute("href"),rootConfig),
success : function(xhr) {
try {
var _ = this.passData;
xhr = safariimportincludefix(xhr,_.rootConfig);
var imports = $.merge(childNodes(xhr.getElementsByTagName("stylesheet")[0],"param"),childNodes(xhr.getElementsByTagName("stylesheet")[0],"template"));
var excistingNodes = [];
try
{
var sheet = _.xObj;
var params = childNodes(sheet,"param");
var stylesheets = childNodes(sheet,"template");
existingNodes = $.merge(params,stylesheets);
}
catch(exception)
{
var x = exception;
}
var existingNames = [];
var existingMatches = [];
for(var a=0;a<existingNodes.length;a++) {
if(existingNodes[a].getAttribute("name")) {
existingNames[existingNodes[a].getAttribute("name")] = true;
} else {
existingMatches[existingNodes[a].getAttribute("match")] = true;
}
}
var pn = _.node.parentNode;
for(var y=0;y<imports.length;y++) {
if(!existingNames[imports[y].getAttribute("name")] && !existingMatches[imports[y].getAttribute("match")]) {
var clonednode = _.xObj.ownerDocument.importNode(imports[y],true);
//pn.insertBefore(clonednode,_.xObj);
pn.insertBefore(clonednode,childNodes(_.xObj,"template")[0]);
}
}
pn.removeChild(_.node);
} catch(ex) {
}
}
});
}
return xObj;
};
Now using the previously pasted test index.html use this for transform.xsl:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:include href="include.xsl" />
<xsl:output method="html"/>
<xsl:template match="/">
<xsl:call-template name="giveMeAnIncludedHeader" />
</xsl:template>
</xsl:stylesheet>
And this for include.xsl
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="giveMeAnIncludedHeader">
<h1>Test</h1>
</xsl:template>
</xsl:stylesheet>
With the previously posted fix in jquery.transform.js this will now insert the included <h1>Test</h1> on all the browsers.
You can see it in action here: http://www.mpdreamz.nl/xsltest
This is not an answer to the original question but during my search over internet looking for a sample xslt transformation that works on chrome I found links to this thread many times. I was looking for a solution that doesn't use any open-source or third party libraries/plugins and works well with silverlight.
The problem with chrome and safari is the limitation that prevents loading xml files directly. The suggested workaround at http://www.mindlence.com/WP/?p=308 is to load the xml file via any other method and pass it as a string to the xslt processor.
With this approach I was able to perform xsl transformations in javascript and pass on the result to silverlight app via HTML Bridge.