How to access local XML in javascript? - javascript

I have a html file, where I keep some notes and other info, I frequently update it, so it got quite big. The problem with that was, that if I change something in the layout, it gets really cumbersome, because I have to change it in so many places. So I had the idea, to put all the data into a XML and transform it into HTML with XSLT.
This immediately brought me to the first issue: I'm not able to access the XML.
The first thing I tried was loading it through XMLHttpRequest:
function loadXMLDoc(filename)
{
if (window.ActiveXObject)
{
xhttp = new ActiveXObject("Msxml2.XMLHTTP");
}
else
{
xhttp = new XMLHttpRequest();
}
xhttp.open("GET", filename, false);
xhttp.setRequestHeader('Content-Type', 'application/xml');
try {xhttp.responseType = "msxml-document"} catch(err) {} // Helping IE11
xhttp.send("");
return xhttp.responseXML;
}
But this gets blocked with "Reason: CORS request not HTTP". I know why I get it and I also know that there most likely is no way around that when using XMLHttpRequest. (except tampering with local browser security, which I don't want to do).
My next idea was to put the XML as string directly into the script and just parse it into a XML doc. Something like:
var rawXml = "
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<bar/>
<bar/>
</foo>
";
But this gets me a "Uncaught SyntaxError: "" string literal contains an unescaped line". So apparently javascript doesn't support any form of verbatim strings and I have to escape all the linebreaks with a \n. My problem with that is, that I'm going to loose the pretty formatting. So reading and editing the XML is going to be a pain. That's definitely something I want to avoid.
EDIT:
Thanks to #Taplar for pointing out, that I can use a template literal, which makes the latter approach work.
This solution is not optimal, since I use NotePad++ and I can either use syntax highlighting for HTML or XML, plus XML Tools syntax autocheck gets screwed over by all the HTML code. But so far it is the best solution I have. Should there be any other options left, I'd like to hear them!
(As other people already pointed out to use input type=file, this is no real viable solution for me. I want to open the HTML document and read it. But with the input elements I have to first pick the XML and the pick the XSL. That's kinda cumbersome over which I prefer the xml-as-string solution)

You should set the XMLHttpRequestInstance.responseType to 'document':
function loadXMLDoc(filename, func){
const x = new XMLHttpRequest;
x.open('GET', filename); x.responseType = 'document';
x.onload = d=>{
func(d);
}
x.send();
return x;
}
// here's how you would execute
loadXMLDoc('yourFile.xml', d=>{
const productNodeList = d.getElementsByTagName('product');
});

Related

How to fix unclosed div issue in javascript?

In a page I am getting from a server, part of the html code has this
<div class="item" />
Apparently browsers don't like the self closed div, and renders as if the slash is not there, which means there is a unclosed div tag. This results on the whole page looking terrible.
Also we can assume that I can't modify the code in the server side that returns that. So basically I am looking for a javascript hack that can fix it.
I tried a string replace on the innerHTML, but it seems to not reform and fix the page after. After it loads the first time, it seems like its permanent.
Does anyone know anyway to fix this?
Thanks
This will "fix" all divs with class item
[].forEach.call(document.querySelectorAll('.item'), function(root) {
var frag = document.createDocumentFragment();
while(root.firstChild) {
frag.appendChild(root.firstChild);
}
root.parentNode.insertBefore(frag, root.nextSibling);
});
You can't fix it properly with JS. JS accesses the DOM resulting from parsing the source code. And then it's too late, the HTML parser has alredy messed up your well-formed XHTML.
What you should do is serve your XHTML as XHTML, not as HTML.
If you can't do that, and really want a JS solution, I guess you could use AJAX to retrieve the source code of the same page, parse it with a DOMParser, and replace the malformed tree with that one.
var ajax = new XMLHttpRequest();
ajax.addEventListener("load", function() {
var code = this.responseText;
var doc = new DOMParser().parseFromString(code, "application/xhtml+xml");
document.replaceChild(doc.documentElement, document.documentElement);
});
ajax.open("GET", location.href);
ajax.send();
But that would download the same code twice, what a waste. And it's not foolproof, HTML parsers are allowed to abort at the first parse error that they encounter.
If you have access to the source code, say:
function fixClosedDivs(src) {
return src.replace(new RegExp('<div([^<]*)\/>', 'gi'), '<div$1></div>');
}
var htm = '<div class="item"/>Hi<br/>Bye<div class="item"/>Hi<div/>Bye';
console.log(fixClosedDivs(htm));
// <div class="item"></div>Hi<br/>Bye<div class="item"></div>Hi<div></div>Bye

xslt with xpath that get some information from xml file doesn't work in JavaScript

I've got an xml file. It is meant for being transformed by xslt processor. The specific template is ready, however it use some information from two additional xml files. All information is used to produce the proper output.
It works fine when I open the main xml file with my browser. The problem is: the result is just a fragment of website, it is an HTML element ready for being appended as a child. That is why I want to transform the xml with the xslt processor within a JavaScript function. Unfortunatelly, the result is half-way done. All what don't need the additional information from these two xml files imported by xpath expression is transformed well. The rest is shortly speaking absent.
JavaScript:
var xhttp = new XMLHttpRequest()
var xsltProcessor = new XSLTProcessor()
xhttp.open("GET", "contentTemplate.xsl", false)
xhttp.send()
xsltProcessor.importStylesheet(xhttp.responseXML)
function buildElement(what) {
var xmlDoc = document.implementation.createDocument("", "root", null)
xmlDoc.documentElement.appendChild(xmlDoc.createElement(what))
var resultDocumentFragment = xsltProcessor.transformToFragment(xmlDoc, document)
return resultDocumentFragment
}
xslt:
there is lots of stuff, I paste just the xslt with xpath expression
<xsl:variable name="extInfo" select="document('tagAvailableToAdd.xml')/root"/>
<xsl:for-each select="$extInfo/tag">
<option>
<xsl:attribute name="value"><xsl:value-of select="tagName"/></xsl:attribute>
<xsl:value-of select="description"/>
</option>
</xsl:for-each>
and that is just absent. Just like no information was delivered.
EDIT:
it works in firefox, doesn't in chrome. I need to improve it. Actually, I don't know how.
xslt:
there is lots of stuff, I paste just
the xslt with xpath expression
<xsl:variable name="extInfo" select="document('tagAvailableToAdd.xml')/root"/>
<xsl:for-each select="$extInfo/tag">
<option>
<xsl:attribute name="value"><xsl:value-of
select="tagName"/>
and that is just absent. Just like no
information was delivered.
Some possible reasons for this behaviour:
The URI of the XML file is not the right one. This is a relative URI and this specific URI will mace the XSLT processor look for a file named 'tagAvailableToAdd.xml' and residing at the base-uri of the stylesheet. However, in this case the stylesheet is obtained dynamically and this means it doesn't have any base-uri. This is the most possible reason for the problem.
The Javascript doesn't have permissions to access files in the local file system.
The document() function isn't allowed by default by the XSLT processor.
The text contained in the file is not a well-formed XML document.
The top element of the XML file is not named root.
Solution: Specify an absolute URI as the argument to the document() function.
I thought I had solved the problem, however an issue in firefox has occured.
Nevertheless, I concern chrome my native browser, that is why i'm glad I made it work in this program. That is the change I implemented in JavaScript:
function talkToServer(address, synch, func) {
func = typeof(func) != 'undefined' ? func : null
xhttp.open(method, address, synch)
xhttp.onreadystatechange = func
xhttp.send()
}
function getXPath(query) {
return document.evaluate(query, xhttp.responseXML, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null)
}
function buildElement(what) {
var xmlDoc = document.implementation.createDocument("", "root", null)
xmlDoc.documentElement.appendChild(xmlDoc.createElement(what))
switch(what) {
case "windowElement":
talkToServer("tagAvailableToAdd.xml", false)
var additionalInfo = getXPath("/root/tag")
var aim = xmlDoc.documentElement.getElementsByTagName("windowElement")[0]
for(i=0;i<additionalInfo.snapshotLength;i++)
aim.appendChild(additionalInfo.snapshotItem(i).cloneNode(true))
talkToServer("cssTemplates.xml", false)
additionalInfo = getXPath("/root/*")
aim.appendChild(xmlDoc.createElement("css"));
aim = aim.getElementsByTagName("css")[0]
for(i=0;i<additionalInfo.snapshotLength;i++)
aim.appendChild(additionalInfo.snapshotItem(i).cloneNode(true))
break;
}
var resultDocumentFragment = xsltProcessor.transformToFragment(xmlDoc, document)
return resultDocumentFragment
}
in xslt now I have all information in , so there is no need to import any external info.
main function is buildElement. I'm sure everybody can see what it does. It'a aim is to provide sth I can "paste" to HTML document.
In chrome it works. In firefox says: Node cannot be used in a document other than the one in which it was created" code: "4, and points at return statement in getXPath function. I don't know how ti fix it, but who cares, it is just firefox (I know it's stupid). In IE it suck, because xhttp is XHttpRequest object, but I believe, that when I provide ActiveX it should give what I want.
If you feel you can help me with the firefix issue, write a comment.

Simplest possible method: html break in XML doc

I have a c program which outputs a number of lines to another c program which stuffs them in a PHP page which is loaded with AJAX. The problem is that the output is a number of lines, which is fine to look at, but which, when viewed as HTML, lack line breaks.
The initial thought I had was obviously to put line breaks in with the output. -- That worked fine, especially since I was using responseText to handle the AJAX output. Now I have discovered that along with the raw text, a bit of metadata also needs to be part of the AJAX response. I jumped over to using responseXML, only to find that the tags no longer worked correctly. At this point I could slog through any number of tutorials to figure out how to work some more complicated mechanism, but I really just want a hack. Could I embed the metadata in an html comment and use the DOM to dig it out (I looked and don't see a good method to get to comments using the dom...)? Could I use the xml directly as html somehow? Could I use CDATA in the xml document(this doesn't seem hopeful)? Could I just use newlines until the code reaches the webpage and then have JS insert the br tags?
I don't need any other formatting, just line breaks, and all this needs to do is work, the less complex the better.
How about using a XSLT stylesheet to format your incoming XML. Save the following as an .html file for an example. Sources : http://www.w3schools.com/xsl/xsl_client.asp & http://www.w3schools.com/dom/dom_parser.asp
<html>
<head>
<script>
//YOUR XML FROM AJAX
var XML = "<top><meta><itemone>test meta</itemone></meta><rows><row>line one</row><row>line two</row><row>line three</row></rows></top>";
//A stylesheet to format the lines that come back.
var XSLT = '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="/"><h2>Lines</h2><xsl:for-each select="descendant::row"><xsl:value-of select="self::*"/><br /></xsl:for-each></xsl:template></xsl:stylesheet>'
function loadXMLDoc(xml)
{
var tempXML;
//IE
if (window.ActiveXObject)
{
tempXML=new ActiveXObject("Microsoft.XMLDOM");
tempXML.loadXML(xml);
}
else if(window.DOMParser)
{
parser=new DOMParser();
tempXML=parser.parseFromString(xml,"text/xml");
}
return tempXML;
}
function displayResult()
{
var xmlDoc = loadXMLDoc(XML);
var xsltDoc = loadXMLDoc(XSLT);
// code for IE
if (window.ActiveXObject)
{
var ex=xmlDoc.transformNode(xsltDoc);
document.getElementById("example").innerHTML=ex;
}
// code for Mozilla, Firefox, Opera, etc.
else if (document.implementation && document.implementation.createDocument)
{
var xsltProcessor=new XSLTProcessor();
xsltProcessor.importStylesheet(xsltDoc);
var resultDocument = xsltProcessor.transformToFragment(xmlDoc,document);
document.getElementById("example").appendChild(resultDocument);
}
}
</script>
</head>
<body onload="displayResult()">
<div id="example" />
</body>
</html>
Thanks for all the good suggestions, but I eventually decided to just prepend a fixed number of descriptor bytes to each text response and then use the substring command to get either the descriptor bytes or the main text response.
This allows me to keep using the simpler response-text mechanism, and is otherwise uncomplicated.
I would have used custom headers but I realized that that would have required buffering the whole output in yet ANOTHER place since the php script actually only contains a single system() call, and has no idea what the C program behind it is doing.

JavaScript - AJAX : Accessing an XML File from a Server

I am trying to access an XML file from a server in my javascript code.
I have an XML file like this:
-<stream version="1.2">
-<room id="simulator" time="128168557915">
-<dimention id=0 x="1.25" y="2.00">
<m mcu="160" sid="75">
</dimention>
</room>
-<room id="simulator" time="128168557928">
-<dimention id=0 x="1.95" y="1.86">
<m mcu="160" sid="55">
</dimention>
</room>
</stream>
this file is generated by an application and I can access it from a URL ( since I am using the simulator for this application the XML is accessible from http://localhost:8081/feed/demo)
This xml file is updated every few seconds and constantly growing.
I have a javascript code which I've added the following code to it in order to use the data from XML file:
<script type="text/javascript">
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("GET","http://localhost:8081/feed/demo",false);
xmlhttp.send();
xmlDoc=xmlhttp.responseXML;
document.write("<table border='1'>");
var x=xmlDoc.getElementsByTagName("room");
for (i=0;i<x.length;i++)
{
document.write("<tr><td>");
document.write(xmlDoc.getElementsByTagName("dimention")[i].getAttribute("x"));
document.write("</td><td>");
}
document.write("</table>");
</script>
Now here comes my problem: if I have the XML file saved on same drive as html page and I address it like this:
xmlhttp.open("GET","floor.xml",false);
it works fine, but when I pass the URL it doesn't. is there anything else I should do in case of loading the xml from URL?
my second question is that I want to use the text values returned by
xmlDoc.getElementsByTagName("dimention")[i].getAttribute("x")
in an if statement like this :
if (valuereturned = 2.00)
{
do sth
}
what is the best way to do that, since the returned value is a text.
I need the answer ASAP and I realy appriciate your help :-)
I know this is a tired and cliche answer for questions like this, but consider using jQuery.
It makes pulling data via AJAX much nicer, and things like your second question much easier.
What's the status code returned when you try to access via absolute URL?
Now here comes my problem: if I have the XML file saved on same drive as html page and I address it like this: xmlhttp.open("GET","floor.xml",false); it works fine, but when I pass the URL it doesn't. is there anything else I should do in case of loading the xml from URL?
Answer: You're being tripped by the same domain security feature of browsers. The Ajax call must be to the same domain that the page itself was loaded from.
my second question is that I want to use the text values returned by
xmlDoc.getElementsByTagName("dimention")[i].getAttribute("x")
in an if statement like this :
if (valuereturned = 2.00)
{do sth}
what is the best way to do that, since the returned value is a text.
Answer:
First off, you want the equality test (==) not assignment (=).
Second, type coercion may work (but you might have to reverse the operands):
if (2.00 == valuereturned)
{do sth}
But much better is to convert explicitly:
if (parseFloat(valuereturned) == 2.00)
{do sth}
If you really want to compare to 2 (rather than a float 2.0), then you'll be safer (more reliable) comparing integers:
if (parseInt(valuereturned) === 2)
{do sth}
If you stick with floats, you'll probably want to do some rounding since looking for exactly matching float values is usually not what you want.
Try this quick and dirty solution.
function includeJS(filename, callback, responcedata){
var page = document.getElementsByTagName('head')[0],
js = document.createElement('script'),
url = "http://query.yahooapis.com/v1/public/yql?q="+
"select%20*%20from%20xml%20where%20url%3D'"+encodeURIComponent(filename)+
"'%20and%20columns%3D'question%2Canswer'&format='+responcedata'+&callback=?";
js.setAttribute('type', 'text/javascript');
js.setAttribute('src', url);
page.appendChild(js);
}
window.onload = includeJS;
Arguments:
filename - the url of your xml file.
responcedata - json or xml
callback - a function that accepts your responcedata, json returns an object, xml returns xml.
YQL For more information.

What is the best method to detect xml in JavaScript

What is the best method to detect xml in JavaScript
e.g. is it possible to detect the mime type of a document - particularly if it is text/xml in JavaScript.
this needs to work in Chrome.
thanks,
Josh
If you are using XMLHttpRequest to get this data, then you can simply check for the Content-Type header using the getResponseHeader method (granted that the server sends the appropriate headers).
var getFile = function(address, responseHandler) {
var req = new XMLHttpRequest();
req.open('get', address, true);
req.onreadystatechange = responseHandler;
req.send(null);
}
var responseHandler = function(resp) {
if ( this.readyState < 4 ) { return; }
console.log(this.getResponseHeader("Content-Type"));
};
getFile("http://zebrakick.com/some/file", responseHandler);
(I seem to be using this code sample a lot...)
You can't determine what the mime-type is with Javascript. I would recommend doing checks on the data returned to see if it is valid XML before you try to parse it. (I'm only assuming what you're trying to do. I can provide a more rigid example if you clarify what your goal is.)
I came across this when looking to determine that a chrome extension script was on an XML page. Maybe this saves someone a few minutes.
In the chrome console and content scripts you can check with:
document.contentType==="application/xml"

Categories

Resources