Convert subscript from OpenMath to MathML - javascript

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();
});
}());

Related

write script without CDATA and Merge two scripts with same functions

I have these scripts which are almost the same but I'm unable to merge them into one..
also I want remove "CDATA" and keep the script functioning in blogger XML template
<script type='text/javascript'>// <![CDATA[
!function(){const e=document.querySelectorAll(".vplayer");for(var t=0;t<e.length;t++){console.log(e[t].dataset.v);const a="//i.ytimg.com/vi_webp/"+e[t].dataset.v+"/hqdefault.webp";var n=new Image;n.src=a,n.addEventListener("load",void e[t].appendChild(n)),e[t].addEventListener("click",function(){const e=document.createElement("iframe");e.setAttribute("allowfullscreen",""),e.setAttribute("frameborder","0"),e.setAttribute("src","//www.youtube.com/embed/"+this.dataset.v+"?rel=0&showinfo=0&autoplay=1&iv_load_policy=3&modestbranding=1&noCookie=false&origin=https%3A%2F%2Fwww.xotaku.com&widgetid=1"),this.innerHTML="",this.appendChild(e)})}}();// ]]></script>
and that the second
<script type='text/javascript'>// <![CDATA[
!function(){const e=document.querySelectorAll(".vplayerold");for(var t=0;t<e.length;t++){console.log(e[t].dataset.v);const a="//i.ytimg.com/vi/"+e[t].dataset.v+"/hqdefault.jpg";var n=new Image;n.src=a,n.addEventListener("load",void e[t].appendChild(n)),e[t].addEventListener("click",function(){const e=document.createElement("iframe");e.setAttribute("allowfullscreen",""),e.setAttribute("frameborder","0"),e.setAttribute("src","//www.youtube.com/embed/"+this.dataset.v+"?rel=0&showinfo=0&autoplay=1&iv_load_policy=3&modestbranding=1&noCookie=false&origin=https%3A%2F%2Fwww.xotaku.com&widgetid=1"),this.innerHTML="",this.appendChild(e)})}}();// ]]></script>
the scripts are the same and I dont want write the whole of it twice
I want this
const e = document.querySelectorAll(".vplayer");
to work with that
const a = "//i.ytimg.com/vi_webp/" + e[t].dataset.v + "/hqdefault.webp";
and this
const e = document.querySelectorAll(".vplayerold");
to work with that
const a="//i.ytimg.com/vi/"+e[t].dataset.v+"/hqdefault.jpg";
the rest of scripte work with both as well
I want remove "CDATA" and keep the script functioning in blogger XML template
That's not possible. It's pretty much required for valid XML unless you want to use escape sequences for <>'".
the scripts are the same and I dont want write the whole of it twice
Make that IEFE a named function declaration, give it parameters, call it twice with different arguments.
<script type="text/javascript">//<![CDATA[
function createPlayer(selector, makeUrl) {
const e = document.querySelectorAll(selector);
for (var t = 0; t < e.length; t++) {
console.log(e[t].dataset.v);
const a = makeUrl(e[t].dataset.v);
var n = new Image;
n.src = a;
n.addEventListener("load", void e[t].appendChild(n));
e[t].addEventListener("click", function() {
const e = document.createElement("iframe");
e.setAttribute("allowfullscreen", "");
e.setAttribute("frameborder", "0");
e.setAttribute("src", "//www.youtube.com/embed/" + this.dataset.v + "?rel=0&showinfo=0&autoplay=1&iv_load_policy=3&modestbranding=1&noCookie=false&origin=https%3A%2F%2Fwww.xotaku.com&widgetid=1");
this.innerHTML = "";
this.appendChild(e);
})
}
}
createPlayer(".vplayer", v => "//i.ytimg.com/vi_webp/" + v + "/hqdefault.webp");
createPlayer(".vplayerold", v => "//i.ytimg.com/vi/" + v + "/hqdefault.jpg");
//]]></script>
Merged example
You mean like this?
<script type='text/javascript'>// <![CDATA[
!function(){const e=document.querySelectorAll(".vplayer");for(var t=0;t<e.length;t++){console.log(e[t].dataset.v);const a="//i.ytimg.com/vi_webp/"+e[t].dataset.v+"/hqdefault.webp";var n=new Image;n.src=a,n.addEventListener("load",void e[t].appendChild(n)),e[t].addEventListener("click",function(){const e=document.createElement("iframe");e.setAttribute("allowfullscreen",""),e.setAttribute("frameborder","0"),e.setAttribute("src","//www.youtube.com/embed/"+this.dataset.v+"?rel=0&showinfo=0&autoplay=1&iv_load_policy=3&modestbranding=1&noCookie=false&origin=https%3A%2F%2Fwww.xotaku.com&widgetid=1"),this.innerHTML="",this.appendChild(e)})}}();
!function(){const e=document.querySelectorAll(".vplayerold");for(var t=0;t<e.length;t++){console.log(e[t].dataset.v);const a="//i.ytimg.com/vi/"+e[t].dataset.v+"/hqdefault.jpg";var n=new Image;n.src=a,n.addEventListener("load",void e[t].appendChild(n)),e[t].addEventListener("click",function(){const e=document.createElement("iframe");e.setAttribute("allowfullscreen",""),e.setAttribute("frameborder","0"),e.setAttribute("src","//www.youtube.com/embed/"+this.dataset.v+"?rel=0&showinfo=0&autoplay=1"),this.innerHTML="",this.appendChild(e)})}}();
// ]]>
</script>
Adding them in separate script tags should also work, depending what your backend allows you to do.

pass an array from pug (jade) to jquery script

I have a array fields which contain a list of strings:
var fields = ['foo', 'bar', 'zed'];
I pass it to pug from express like this:
app.get('/some_route', function(req, res) {
res.render('some_view', { fields: fields });
});
Now I want to use that array inside jquery script,
I already try:
<script>
$( document ).ready(function() {
var fields = #{fields};
// return: var fields = foo,bar,zed;
});
</script>
and:
<script>
$( document ).ready(function() {
var fields = JSON.parse(#{fields});
// return: var fields = JSON.parse(foo,bar,zed);
});
</script>
thanks
JSON-encode it an put it in an attribute somewhere, like on the <script> itself:
script(id='field-source', data-fields=JSON.stringify(fields)).
$(document).ready(function () {
var fields = JSON.parse($('#field-source').data('fields'));
});
It’s possible to put it directly into the script with some careful escaping¹ (JSON-encoding is not enough!), but not worth the effort when attributes already work so reliably.
¹ You start by JSON-encoding, then make it safe for the JavaScript context by replacing U+2028 and U+2029 with \u202[89], then make it safe for the HTML context by replacing < with \x3c. Replacing only </ is not enough, as <!-- can also mess with parsing in certain contrivable ways.

Extract only javascript from a script tag

I would like to extract only javascript from script tags in a HTML document which I want to pass it to a JS parser like esprima. I am using nodejs to write this application and have the content extracted from the script tag as a string.
The problem is when there are HTML comments in the javascript extracted from html documents which I want to remove.
<!-- var a; --> should be converted to var a
A simple removal of <-- and --> does not work since it fails in the case <!-- if(j-->0); --> where it removes the middle -->
I would also like to remove identifiers like [if !IE] and [endif] which are sometimes found inside script tags.
I would also like to extract the JS inside CDATA segments.
<![CDATA[ var a; ]]> should be converted to var a
Is all this possible using a regex or is something more required?
In short I would like to sanitize the JS from script tags so that I can safely pass it into a parser like esprima.
Thanks!
EDIT:
Based on #user568109 's answer. This is the rough code that parses through HTML comments and CDATA segments inside script tags
var htmlparser = require("htmlparser2");
var jstext = '';
var parser = new htmlparser.Pavar htmlparser = require("htmlparser2");
var jstext = '';
var parser = new htmlparser.Parser({
onopentag: function(name, attribs){
if(name === "script" && attribs.type === "text/javascript"){
jstext = '';
//console.log("JS! Hooray!");
}
},
ontext: function(text) {
jstext += text;
},
onclosetag: function(tagname) {
if(tagname === "script") {
console.log(jstext);
jstext = '';
}
},
oncomment : function(data) {
if(jstext) {
jstext += data;
}
}
}, {
xmlMode:true
});
parser.write(input);
parser.end()
That is the job of the parser. See the htmlparser2 or esprima itself. Please don't use regex to parse HTML, it is seductive. You will waste your precious time and effort trying to match more tags.
An example from the page:
var htmlparser = require("htmlparser2");
var parser = new htmlparser.Parser({
onopentag: function(name, attribs){
if(name === "script" && attribs.type === "text/javascript"){
console.log("JS! Hooray!");
}
},
ontext: function(text){
console.log("-->", text);
},
onclosetag: function(tagname){
if(tagname === "script"){
console.log("That's it?!");
}
}
});
parser.write("Xyz <script type='text/javascript'>var foo = '<<bar>>';</script>");
parser.end();
Output (simplified):
--> Xyz
JS! Hooray!
--> var foo = '<<bar>>';
That's it?!
It will give you all the tags divs, comments, scripts etc. But you would have to validate the script inside the comments yourself. Also CDATA is a valid tag in XML(XHTML), so htmlparser2 would detect it as a comment, you would have to check those too.

easiest way to read data from excel spreadsheet with javascript?

I have a list of airport codes, names, and locations in an Excel Spreadsheet like the below:
+-------+----------------------------------------+-------------------+
| Code | Airport Name | Location |
+-------+----------------------------------------+-------------------+
| AUA | Queen Beatrix International Airport | Oranjestad, Aruba|
+-------+----------------------------------------+-------------------+
My Javascript is passed a 3 character string that should be an airline code. When that happens I need to find the code on the spreadsheet and return the Airport Name and Location.
Im thinking something like:
var code = "AUA";
console.log(getAirportInfo(code));
function getAirportInfo(code) {
// get information from spreadsheet
//format info (no help needed there)
return airportInfo;
}
Where the log would write out:
Oranjestad, Aruba (AUA): Queen Beatrix International Airport
What is the easiest method to get the data I need from the spreadsheet?
Extra Info:
The spreadsheet has over 17,000 entries
The function alluded to above may be called up to 8 times in row
I don't have to use an Excel Spreadsheet thats just what I have now
I will never need to edit the spreadsheet with my code
I did search around the web but everything I could find was much more complicated than what Im trying to do so it made it hard to understand what Im looking for.
Thank you for any help pointing me in the right direction.
I ended up using a tool at shancarter.com/data_converter to convert my flie to a JSON file and linked that to my page. Now I just loop through that JSON object to get what I need. This seemed like the simplest way for my particular needs.
I've used a plain text file(csv, or tsv both of which can be exported directly from Excel)
Loaded that into a string var via xmlhttprequest. Usually the browsers cache will stop having to download the file on each page load.
Then have a Regex parse out the values as needed.
All without using any third party....I can dig the code out if you wish.
Example:
you will need to have the data.txt file in the same web folder as this page, or update the paths...
<html>
<head>
<script>
var fileName = "data.txt";
var data = "";
req = new XMLHttpRequest();
req.open("GET", fileName, false);
req.addEventListener("readystatechange", function (e) {
data = req.responseText ;
});
req.send();
function getInfoByCode(c){
if( data == "" ){
return 'DataNotReady' ;
} else {
var rx = new RegExp( "^(" + c + ")\\s+\\|\\s+(.+)\\s+\\|\\s+\\s+(.+)\\|", 'm' ) ;
var values = data.match(rx,'m');
return { airport:values[2] , city:values[3] };
}
}
function clickButton(){
var e = document.getElementById("code");
var ret = getInfoByCode(e.value);
var res = document.getElementById("res");
res.innerText = "Airport:" + ret.airport + " in " + ret.city;
}
</script>
</head>
<body>
<input id="code" value="AUA">
<button onclick="clickButton();">Find</button>
<div id="res">
</div>
</body>
</html>

Create XML in 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>

Categories