Create XML in JavaScript - javascript

Is it possible to create an XML file with some data in JavaScript? I have the data stored in variables.
I've googled around a bit and it doesn't seem like it's talked about much. I thought I could use XMLWriter such as this:
var XML = new XMLWriter();
XML.BeginNode ("testing");
XML.Node("testingOne");
XML.Node("TestingTwo");
XML.Node("TestingThree");
XML.EndNode();
as stated in this tutorial: EHow Tutorial
However, when I execute this code, I get the following error:
ReferenceError: XMLWriter is not defined
How can I solve this error?

Disclaimer: The following answer assumes that you are using the JavaScript environment of a web browser.
JavaScript handles XML with 'XML DOM objects'.
You can obtain such an object in three ways:
1. Creating a new XML DOM object
var xmlDoc = document.implementation.createDocument(null, "books");
The first argument can contain the namespace URI of the document to be created, if the document belongs to one.
Source: https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createDocument
2. Fetching an XML file with XMLHttpRequest
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
var xmlDoc = xhttp.responseXML; //important to use responseXML here
}
xhttp.open("GET", "books.xml", true);
xhttp.send();
3. Parsing a string containing serialized XML
var xmlString = "<root></root>";
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(xmlString, "text/xml"); //important to use "text/xml"
When you have obtained an XML DOM object, you can use methods to manipulate it like
var node = xmlDoc.createElement("heyHo");
var elements = xmlDoc.getElementsByTagName("root");
elements[0].appendChild(node);
For a full reference, see http://www.w3schools.com/xml/dom_intro.asp
Note:
It is important, that you don't use the methods provided by the document namespace, i. e.
var node = document.createElement("Item");
This will create HTML nodes instead of XML nodes and will result in a node with lower-case tag names. XML tag names are case-sensitive in contrast to HTML tag names.
You can serialize XML DOM objects like this:
var serializer = new XMLSerializer();
var xmlString = serializer.serializeToString(xmlDoc);

Consider that we need to create the following XML document:
<?xml version="1.0"?>
<people>
<person first-name="eric" middle-initial="H" last-name="jung">
<address street="321 south st" city="denver" state="co" country="usa"/>
<address street="123 main st" city="arlington" state="ma" country="usa"/>
</person>
<person first-name="jed" last-name="brown">
<address street="321 north st" city="atlanta" state="ga" country="usa"/>
<address street="123 west st" city="seattle" state="wa" country="usa"/>
<address street="321 south avenue" city="denver" state="co" country="usa"/>
</person>
</people>
we can write the following code to generate the above XML
var doc = document.implementation.createDocument("", "", null);
var peopleElem = doc.createElement("people");
var personElem1 = doc.createElement("person");
personElem1.setAttribute("first-name", "eric");
personElem1.setAttribute("middle-initial", "h");
personElem1.setAttribute("last-name", "jung");
var addressElem1 = doc.createElement("address");
addressElem1.setAttribute("street", "321 south st");
addressElem1.setAttribute("city", "denver");
addressElem1.setAttribute("state", "co");
addressElem1.setAttribute("country", "usa");
personElem1.appendChild(addressElem1);
var addressElem2 = doc.createElement("address");
addressElem2.setAttribute("street", "123 main st");
addressElem2.setAttribute("city", "arlington");
addressElem2.setAttribute("state", "ma");
addressElem2.setAttribute("country", "usa");
personElem1.appendChild(addressElem2);
var personElem2 = doc.createElement("person");
personElem2.setAttribute("first-name", "jed");
personElem2.setAttribute("last-name", "brown");
var addressElem3 = doc.createElement("address");
addressElem3.setAttribute("street", "321 north st");
addressElem3.setAttribute("city", "atlanta");
addressElem3.setAttribute("state", "ga");
addressElem3.setAttribute("country", "usa");
personElem2.appendChild(addressElem3);
var addressElem4 = doc.createElement("address");
addressElem4.setAttribute("street", "123 west st");
addressElem4.setAttribute("city", "seattle");
addressElem4.setAttribute("state", "wa");
addressElem4.setAttribute("country", "usa");
personElem2.appendChild(addressElem4);
var addressElem5 = doc.createElement("address");
addressElem5.setAttribute("street", "321 south avenue");
addressElem5.setAttribute("city", "denver");
addressElem5.setAttribute("state", "co");
addressElem5.setAttribute("country", "usa");
personElem2.appendChild(addressElem5);
peopleElem.appendChild(personElem1);
peopleElem.appendChild(personElem2);
doc.appendChild(peopleElem);
If any text need to be written between a tag we can use innerHTML property to achieve it.
Example
elem = doc.createElement("Gender")
elem.innerHTML = "Male"
parent_elem.appendChild(elem)
For more details please follow the below link. The above example has been explained there in more details.
https://developer.mozilla.org/en-US/docs/Web/API/Document_object_model/How_to_create_a_DOM_tree

xml-writer(npm package)
I think this is the good way to create and write xml file easy.
Also it can be used on server side with nodejs.
var XMLWriter = require('xml-writer');
xw = new XMLWriter;
xw.startDocument();
xw.startElement('root');
xw.writeAttribute('foo', 'value');
xw.text('Some content');
xw.endDocument();
console.log(xw.toString());

Simply use
var xmlString = '<?xml version="1.0" ?><root />';
var xml = jQuery.parseXML(xml);
It's jQuery.parseXML, so no need to worry about cross-browser tricks. Use jQuery as like HTML, it's using the native XML engine.

this work for me..
var xml = parser.parseFromString('<?xml version="1.0" encoding="utf-8"?><root></root>', "application/xml");
developer.mozilla.org/en-US/docs/Web/API/DOMParser

Only works in IE
$(function(){
var xml = '<?xml version="1.0"?><foo><bar>bar</bar></foo>';
var xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async="false";
xmlDoc.loadXML(xml);
alert(xmlDoc.xml);
});
Then push xmlDoc.xml to your java code.

Your code is referencing this library
You can include it, and then your code in question should run as is. If you want to do this without prepending the library & build it with builtin functions only - follow answer from #Seb3736.
In Browser Example
<html>
<head>
<script src="Global.js" language="javascript"></script>
<script src="XMLWriter.js" language="javascript"></script>
<script language="javascript" type="text/javascript">
function genXML(){
var XML = new XMLWriter();
XML.BeginNode ("testing");
XML.Node("testingOne");
XML.Node("TestingTwo");
XML.Node("TestingThree");
XML.EndNode();
//Do something... eg.
console.log(XML.ToString); //Yes ToString() not toString()
}
</script>
</head>
<body>
<input type="submit" value="genXML" onclick="genXML();">
</body>
</html>

Related

Get XML field value javascript

I have the following XML, it's coming as string from a request. How can I get the capital value (Washington, DC Paris)?
<Country>
<USA>
<Capital>"Washington, D.C"</Capital>
</USA>
<France>
<Capital>"Paris"</Capital>
</France>
</Country>
Use a DomParser :
var xml = `<Country>
<USA>
<Capital>"Washington, D.C"</Capital>
</USA>
<France>
<Capital>"Paris"</Capital>
</France>
</Country>`
var parser = new DOMParser();
var doc = parser.parseFromString(xml, "application/xml");
doc.querySelectorAll('Capital').forEach(
(cap) => console.log(cap.textContent));
Adding the answer with jquery. With jquery it can be easily done as,
var text = `<Country>
<USA>
<Capital>"Washington, D.C"</Capital>
</USA>
<France>
<Capital>"Paris"</Capital>
</France>
</Country>`;
$(text).find("Capital").each(function(){
console.log($(this).text());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

How to perform XSLT transformation in Chrome using variables

I am trying to do an XSL transformation.
However, whenever the variable with a document fragment is referenced, the transformation seems to fail.
I created a JSFiddle to demonstrate the issue. The XML in the example is a dummy document to allow the XSLT to run.
What am I doing wrong?
Javascript:
var xml = [
'<p xmlns="http://www.w3.org/1999/xhtml">',
'<\/p>'
].join('\n');
var xsl = [
'<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">',
'<xsl:variable name="xmlVar">',
'<aaaa value="It works"\/>',
'<\/xsl:variable>',
'<xsl:template match="\/">',
'<ROOT>',
//works ok after commenting out
'<xsl:value-of select="$xmlVar\/aaaa\/#value"\/>',
'<\/ROOT>',
'<\/xsl:template>',
'<\/xsl:stylesheet>'
].join('\n');
var domParser = new DOMParser();
var xmlDoc = domParser.parseFromString(xml, 'application/xml');
var xslDoc = domParser.parseFromString(xsl, 'application/xml');
var xsltProc = new XSLTProcessor();
xsltProc.importStylesheet(xslDoc);
try{
var result = xsltProc.transformToFragment(xmlDoc, document);
} catch(exc) {
document.getElementById('error').innerHTML = exc;
}
function encodeStr(rawStr) { return rawStr.replace(/[\u00A0-\u9999<>\&]/gim,
function(i){
return '&#'+i.charCodeAt(0)+';'
});
}
document.getElementById('xslText').innerHTML = encodeStr(xsl);
document.getElementById('result').innerHTML = encodeStr((new XMLSerializer).serializeToString(result));
HTML:
<pre id='xslText'>
</pre>
<pre id='result'>
</pre>
<pre id='error'>
</pre>
In XSLT 1.0 you need to use an extension function like exsl:node-set (http://exslt.org/exsl/functions/node-set/index.html) to convert a variable value of type result tree fragment (https://www.w3.org/TR/xslt-10/#section-Result-Tree-Fragments) to a node-set to be able to use XPath on the nodes e.g.
var xml = [
'<p xmlns="http://www.w3.org/1999/xhtml">',
'<\/p>'
].join('\n');
var xsl = [
'<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:exsl="http://exslt.org/common" xmlns:msxml="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="exsl msxml">',
'<xsl:variable name="xmlVar">',
'<aaaa value="It works"/>',
'<\/xsl:variable>',
'<xsl:template match="/">',
'<div>',
'<xsl:choose><xsl:when test="function-available(\'exsl:node-set\')"><xsl:value-of select="exsl:node-set($xmlVar)/aaaa/#value"/><\/xsl:when><xsl:when test="function-available(\'msxml:node-set\')"><xsl:value-of select="msxml:node-set($xmlVar)/aaaa/#value"/><\/xsl:when><\/xsl:choose>',
'<\/div>',
'<\/xsl:template>',
'<\/xsl:stylesheet>'
].join('\n');
var domParser = new DOMParser();
var xmlDoc = domParser.parseFromString(xml, 'application/xml');
var xslDoc = domParser.parseFromString(xsl, 'application/xml');
var xsltProc = new XSLTProcessor();
xsltProc.importStylesheet(xslDoc);
try{
var result = xsltProc.transformToFragment(xmlDoc, document);
document.getElementById('result').appendChild(result);
} catch(exc) {
document.getElementById('error').innerHTML = exc;
}
<pre id='xslText'>
</pre>
<pre id='result'>
</pre>
<pre id='error'>
</pre>
Drawback in terms of cross-browser compatibility with client-side XSLT 1 is that Microsoft use MSXML 3 or 6 in IE and Edge to provide XSLT support and unfortunately MSXML has its own proprietary namespace for such an extension function instead of supporting EXSLT.
Fiddle updated to http://jsfiddle.net/29pwf84c/14/.

Convert subscript from OpenMath to MathML

I'm working with mathdox, to insert equations in my web page. I have implemented all the symbols and mathematical expressions that I need, to insert them as openmath and convert them in to MathML, except subscript. I know that it's suppose to work like this:
<OMOBJ xmlns='http://www.openmath.org/OpenMath' version='2.0' cdbase='http://www.openmath.org/cd'>
<OMA style='sub'>
<OMV name='x'/>
<OMI>2</OMI>
</OMA>
</OMOBJ>
should convert to
<math xmlns="http://www.w3.org/1998/Math/MathML">
<msub>
<mi>X</mi>
<mn>2</mn>
</msub>
</math>
but I cannot find a way to implement it in javascript or find it's existing implementation in mathdox.
For me, this only works in Firefox. The main tools for the job are createElementNS and getElementsByTagNameNS. Additionally, I'm not sure where you get your openmath document, but I'm going to be retrieving it via AJAX.
So, assuming your file structure is:
/root
+-/js
| +-convert.js
|
+-/xml
| +-openmath.xml
|
+-index.html
And your files are as follows:
index.html
The only thing to note about index.html is that we set an id on the <math> element that we want to put the converted tags under. We also include the convert.js JavaScript file.
<html>
<head>
<title>Convert</title>
<script src="js/convert.js"></script>
</head>
<body>
<main>
<math xmlns="http://www.w3.org/1998/Math/MathML" id="target"></math>
</main>
</body>
</html>
openmath.xml
This file is just the XML that you posted in your question that we will be converting to the math namespace.
<OMOBJ xmlns='http://www.openmath.org/OpenMath' version='2.0' cdbase='http://www.openmath.org/cd'>
<OMA style='sub'>
<OMV name='x' />
<OMI>2</OMI>
</OMA>
</OMOBJ>
convert.js
The way that convert.js works is that it loads up the openmath document over xhr, then creates a new XML document with the document text using DOMParser() and parseFromString(). Then we feed that document to mathSubscriptConverter() which pulls all the OMA tags, gets the relevant data from them, and then converts them to msub tags. Once we have the msub tags, we add them as children under the <math> tag that exists in our index.html.
(function () {
"use strict";
var mathNS = "http://www.w3.org/1998/Math/MathML",
openMathNS = "http://www.openmath.org/OpenMath",
xhr = new XMLHttpRequest();
function mathSubscriptConverter(openmathDoc) {
var target = document.getElementById("target"),
omas = openmathDoc.getElementsByTagNameNS(openMathNS, "OMA");
// Make sure we have a math element to put this under
if (target) {
// Iterate each OMA tag
Array.prototype.forEach.call(omas, function (oma) {
var omv, omi, msub, mi, mn;
// Get the first OMV
omv = oma.getElementsByTagNameNS(openMathNS, "OMV")[0];
// Get the first OMV
omi = oma.getElementsByTagNameNS(openMathNS, "OMI")[0];
// Create a subscript tag in the math namespace
msub = document.createElementNS(mathNS, "msub");
// Create an mi tag in the math namespace
mi = document.createElementNS(mathNS, "mi");
// Create an mn tag in the math namespace
mn = document.createElementNS(mathNS, "mn");
// Set our math attributes
mi.innerHTML = omv.getAttribute("name");
mn.innerHTML = omi.innerHTML;
// Add our new elements to the target
msub.appendChild(mi);
msub.appendChild(mn);
target.appendChild(msub);
});
}
}
// Wait for document load
document.addEventListener("DOMContentLoaded", function () {
// Load our openmath document
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
var parser = new DOMParser(),
mdoc = parser.parseFromString(xhr.responseText, "application/xml");
mathSubscriptConverter(mdoc);
}
};
xhr.open("GET", "xml/openmath.xml", true);
xhr.send();
});
}());

cannot get xmlDoc to load any value. Keep getting null values

I have an xml file that I retreive via terminal emulation. I want to parse the results into a textarea in html. I am able to view the file in the textarea in xml format but have been unable to parse it into lines of the inner text.
Here is the javascript/jquery:
var x = ""
var y = ""
var Command="";
var cmd=""
$(document).ready(function() {
alert('jquery working');
$('#tester').click(function() {
$("#disptext").val("");
var APOresp = new ActiveXObject("DAT32COM.TERMINALEMULATION");
var Command = "<FORMAT>>*IA</FORMAT>";
APOresp.MakeEntry(Command);
//APOresp.GetMore(true,false);
var x = APOresp.ResponseXML;
APOresp.Close();
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = "false";
xmlDoc.loadXML(x);
$(x).find('RESPONSE').each(function() { //these lines do not work. I get null xmlDoc reference
$("#disptext").val($(this).text() + "<br />");
});
//$("#disptext").val(xmlDoc.xml); //disptext is the textarea
});
Here is what a portion of the text file looks like:
?xml version="1.0"?>
<!--This is a host terminal response-->
<RESPONSE xmlns="x-schema:C:\fp\swdir\Content\emulation-schema.xml">
<LINE INDEX="1"><![CDATA[SIGN IN ]]><CARRIAGE_RETURN/></LINE>
<LINE INDEX="2"><SOM/></LINE>
</RESPONSE>
Most files are much longer.
I want to get the text for each "LINE: tag and loop it into the textarea. It does put in the whole xml file in xml format if I use the last commented out line in the javascript file. For some unknown reason, I am unable to use the xmlDoc. I keep getting errors that the xmlDoc has null values. I have been trying to fix this for a number of days without success. Any help would be greatly appreciated.

is there a .innerXML?

i'd like to ask if anyone here is familiar wif xml who can give me some help...
http://www.plognow.com/xml/login.xml
and i hv a little function tht i use to break it up...
function dialogXML(varName,url){
if (window.XMLHttpRequest){
r[varName]=new XMLHttpRequest();
}else{
r[varName]=new ActiveXObject("Microsoft.XMLHTTP");
}
r[varName].onreadystatechange=function(){
if (r[varName].readyState==4 && r[varName].status==200){
var rep=r[varName].responseXML.getElementsByTagName('box')[0];
var title=rep.getElementsByTagName('title')[0].nodeValue;
var content=rep.getElementsByTagName('content')[0].nodeValue;
createDialog(title,content);
}
}
r[varName].open('GET',url,true);
r[varName].send();
}
well i'm not sure how XMLDOM works, but can i retrieve the inwards of one tag?(all the childs subchilds etc)like u'd do in innerHTML. thanks!
You can use jQuery to manipulate XML documents as well not just HTML documents. HTML documents are XML documents.
if (r[varName].readyState==4 && r[varName].status==200){
var xml = r[varName].responseXML;
var rep = $("box:first", xml);
var title = $("title:first", rep).text();
var content= $("content:first", rep).text();
createDialog(title, content);
}
If your question is how to retrieve xml tree structure then the answer is : using responseXML property of r[varName].

Categories