nodeName returns more often than expected - javascript

I've got some code that's reading an XML document and then using that to build the HTML page. Similar to markdown I suppose. I've simplified the below code but effectively that JS line at the end with CAROUSEL in it is looking at the XML, but it is creating 7 carousel divs instead of 1 like I want. I get why it's returning 7 times (sort of), but how do I get it to only create it once. the ITEM tags inside of the CAROUSEL tag (see the XML section) is to indicate what images should be inside that particular carousel.
JS:
var col9div = null;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
var xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("GET",'xml/index'+page_counter+".xml",false);
xmlhttp.send();
xmlDoc=xmlhttp.responseXML;
var col9div = document.createElement("div");
});
var tempvar = arr.length;
console.log(tempvar);
$(col9div).addClass("col-md-9");
$("#bannersize").append(col9div);
flush();
function flush(){
var activity_element_idcounter = 0;
var module_element_idcounter = 0;
var x=xmlDoc.getElementsByTagName("MODULE");
for (i=0;i<x.length;i++)
{
var getlastli = $(".sidecounter:last");
module_element_idcounter++;
col9div.insertAdjacentHTML('beforeend', '<div class="row"><div class="col-md-12 well"' + ' id="module' + module_element_idcounter + '"><div id="skrollr-div' + module_element_idcounter + '"></div></div>');
var scanner = x[i].getElementsByTagName("*");
for (var q=0;q<scanner.length;q++){
activity_element_idcounter ++;
$.each(scanner[q].childNodes, function(){
else if (scanner[q].nodeName === "CAROUSEL"){
do something here
}
XML:
<MODULE>
<CAROUSEL>
<ITEM>assets/images/index5/tehran-carousel/tehran-day-and-night.jpg</ITEM>
<ITEM>assets/images/index5/tehran-carousel/tehran-day-and-night-1.jpg</ITEM>
<ITEM>assets/images/index5/tehran-carousel/tehran-bazaar-entrance.jpg</ITEM>
</CAROUSEL>
</MODULE>
thanks,
Robbie

I assume this is executing in some kind of loop that you haven't shown us, but you are not using any conditional logic. What you seem to be getting is three separate statements:
// Always just evaluates to false and does nothing; the return value of
// getElementsByTagName() does not have a nodeName property
xmlDoc.getElementsByTagName("MODULE").getElementsByTagName("*").nodeName === "CAROUSEL"
{
// Always executes - simply a statement inside some curly braces
$("#module" + module_element_idcounter).append("...");
}
// Empty statement - does nothing
;
To get it to work the way you want it to, you probably need to use an if statement somewhere, but in order for us to help you, you need to show us more of your code than the tiny sampling you have provided.

Related

Edge and IE11 XSLT space issue

I have ran into an issue with Edge and IE11 using XSLT to convert from HTML to XML.
When converting, elements that contain only spaces (one or many) get turned into an empty or self closing element after transform in Edge and IE11 only; Chrome and Firefox persist the spaces. This is true going from XML to HTML and HTML to XML
I have created a Codepen example of the issue ging from HTML to XML which is an ultra chopped down version of the code to demonstrate with minimal noise what the process I am using is.
https://codepen.io/akealey/pen/YzyEmpz
Run the pen in Chrome and Edge and the result will demonstrate Edge removing the space.
Is there any way to preserve the space(s)? I have gone through all sorts of different attributes and settings to do so but nothing works.
The markup being transformed exists on a webpage (the webpage I have full control over, the document I do not).
var outStr, processor, implementationObject, transformedDocument;
// a trimmed down document all the way to the element in question
var xmlStr = '<div> </div>';
// an alternate bare bones xslt. also does not generate a space in the output
var xsltStr = '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">\n<xsl:output method="xml" encoding="utf-8" indent="no"/>\n<xsl:template match="/">\n<xsl:copy-of select="*" />\n</xsl:template></xsl:stylesheet>';
// create the dom parser
var domParser = new DOMParser();
// parse both xml and xslt into actual dom objects. Note xml has the xml header prepended
var xmlDoc = domParser.parseFromString('<?xml version="1.0" ?>' + xmlStr, 'text/xml');
var xsltDoc = domParser.parseFromString(xsltStr, 'text/xml');
// test what xslt processors are available. if chrome, firefox, edge - else ie11
if (typeof XSLTProcessor !== "undefined" && XSLTProcessor !== null) {
// Chrome
// Edge
// Firefox
processor = new XSLTProcessor();
processor.importStylesheet(xsltDoc);
//edge has the space inside xmlDoc up to this point
transformedDocument = processor.transformToFragment(xmlDoc, document);
// inspecting the tansformed document in Edge shows the element has no space but chrome and firefox does
} else if ('transformNode' in xmlDoc) {
// IE11
transformedDocument = xmlDoc.transformNode(xsltDoc);
} else {
console.log('no transform engine found');
}
// turn the converted xml document into a string
var xmlSerializer = new XMLSerializer();
var transformResult = xmlSerializer.serializeToString(transformedDocument);
console.log(transformResult);
// In Edge .serializeToString() turns the element in to a self closing tag (as there is no content)
var hasSpace = /> <\//.test(transformResult);
console.log(hasSpace);
For IE using MSXML directly I think you need to set preserveWhiteSpace to true on any DOMDocument before using load or loadXML, as the default of that property is false (https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ms761353(v%3Dvs.85)).
For Edge it might help to set up <div xml:space="preserve"> </div>.
Your codepen has errors in IE. transformNode is undefined in IE. You need to use new ActiveXObject('Msxml2.DOMDocument.6.0') and loadXML in IE instead of DOMParser to parse XML. For Edge, I'm in favor of Martin's answer: Apply xml:space="preserve" on the root element then it will apply to all descendants as well.
The final code sample is like this which can work well in IE and Edge (pay attention to the //IE11 parts in the code):
function textOrConsole(text, elementSelector) {
var processorElement = document.querySelector(elementSelector);
if (processorElement)
processorElement.innerText = text;
else
console.log(text);
}
var outStr, processor, implementationObject, transformedDocument, transformResult;
// a trimmed down document all the way to the element in question
var xmlStr = '<div xml:space="preserve"><div> </div></div>';
// an alternate bare bones xslt. also does not generate a space in the output
var xsltStr = '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">\n<xsl:output method="xml" encoding="utf-8" indent="no"/>\n<xsl:template match="/">\n<xsl:copy-of select="*" />\n</xsl:template></xsl:stylesheet>';
// create the dom parser
var domParser = new DOMParser();
// parse both xml and xslt into actual dom objects. Note xml has the xml header prepended
var xmlDoc = domParser.parseFromString('<?xml version="1.0" ?>' + xmlStr, 'text/xml');
var xsltDoc = domParser.parseFromString(xsltStr, 'text/xml');
// test what xslt processors are available. if chrome, firefox, edge - else ie11
if (typeof XSLTProcessor !== "undefined" && XSLTProcessor !== null) {
// Chrome
// Edge
// Firefox
textOrConsole('XSLTProcessor (transformToFragment)', '#transform');
processor = new XSLTProcessor();
processor.importStylesheet(xsltDoc);
//edge has the space inside xmlDoc up to this point
transformedDocument = processor.transformToFragment(xmlDoc, document);
// inspecting the tansformed document in Edge shows the element has no space but chrome and firefox does
} else if (!!window.ActiveXObject || "ActiveXObject" in window) {
// IE11
var docxml = new ActiveXObject('Msxml2.DOMDocument.6.0');
docxml.loadXML(xmlStr);
var docxsl = new ActiveXObject('Msxml2.DOMDocument.6.0');
docxsl.loadXML(xsltStr);
transformedDocument = docxml.transformNode(docxsl);
textOrConsole('xmlDoc.transformNode', '#transform');
} else {
console.log('no transform engine found');
}
// turn the converted xml document into a string
var xmlSerializer = new XMLSerializer();
if (!!window.ActiveXObject || "ActiveXObject" in window) {
// IE11
transformResult = transformedDocument;
} else {
transformResult = xmlSerializer.serializeToString(transformedDocument);
}
// In Edge .serializeToString() turns the element int oa self closing tag (as there is no content)
var hasSpace = /> <\//.test(transformResult);
textOrConsole("Transformed element: " + transformResult, '#text');
textOrConsole("Has space: " + hasSpace, '#hasSpace');
<h3>Result</h3>
<span>Transform used: </span><span id="transform"></span>
<div id="text"></div>
<div id="hasSpace"></div>
</body>

Why does Safari's document.adoptNode() convert css class names to lowercase when source document is in quirks mode?

I am using XHR (XML Http Request) to load an html fragment. I am using responseType = "document" in order to offload the html parsing to the browser. When the ajax call completes, I am using document.adoptNode() to include the ajax html elements in my main document.
I noticed a weird bug that affects Safari only (v9.1.1 on El Capitan and iOS 9.3.2). It seems that when Safari adopts the node, it will convert css class names into lower case. For a full demonstration, see this jsfiddle: https://jsfiddle.net/theblueslate/wxo7zst5/2/
This bug doesn't occur on Chrome v51 or IE11.
The code from the jsfiddle is included here:
function buildDataLoadedCallback (containerId, useAdopt) {
return function() {
var parsedDoc = this.response;
var parsedBodyChild = parsedDoc.body.children[0];
var newNode;
if (useAdopt) {
newNode = document.adoptNode(parsedBodyChild);
} else {
newNode = document.importNode(parsedBodyChild, true);
}
var container = document.getElementById(containerId);
container.appendChild(newNode);
}
}
function requestAjaxHtmlFragment(pageName, callback) {
var xhr = new XMLHttpRequest();
xhr.responseType = "document";
xhr.addEventListener("load", callback);
/* this fragment.html file simply contains:
<div class="myClass">
<p>MyClass</p>
</div>
*/
xhr.open("GET","https://dl.dropboxusercontent.com/u/15211879/js-fiddle/" + pageName + ".html", /*async:*/true);
xhr.send();
}
var pageName = "fragment";
requestAjaxHtmlFragment(pageName, buildDataLoadedCallback(pageName + "-adopt-container", true));
Is there an obvious error that I am missing? I can't spot it, and I have raised a webkit bug: https://bugs.webkit.org/show_bug.cgi?id=159555, but I am hoping I am wrong.
Turns out this was a bug. Now fixed in WebKit: https://bugs.webkit.org/show_bug.cgi?id=159555
I think it is still useful posting this to SO. Posting increases the visibility for anybody else who is struggling with this issue, as I was.

how to limit 12 images displaying from xml file and automatically creating pages for the others

I currently have a xml file that holds 10000 images that link to videos, they are currently displaying on one page. So all 10000 images are on one page. I am trying to get it so that the images only display 12 of them and then automatically creates numerous pages for the rest.
This the codes that is getting the images
<div id="container">
<table id="demo"></table>
<script>
// Initialize
(function() {
loadXMLDoc();
})();
function loadXMLDoc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
myFunction(xmlhttp);
}
};
xmlhttp.open("GET", "amateur.xml", true);
xmlhttp.send();
}
function myFunction(xml) {
var i;
var xmlDoc = xml.responseXML;
var table="<tr></tr>";
var x = xmlDoc.getElementsByTagName("video");
for (i = 0; i <x.length; i++) {
var img = x[i].getElementsByTagName("thumbnail")[0].childNodes[0].nodeValue;
var url = x[i].getElementsByTagName("url")[0].childNodes[0].nodeValue;
table +=
"<a href='"+url+"'><img src='"+img+"'></a>";
}
document.getElementById("demo").innerHTML = table;
}
</script>
</div>
This is a sample of what the XML file looks like, it has been edited slightly as it is inappropriate for the content to be shown. The XML file is called "amateur.xml"
<?xml version="1.0" encoding="utf-8"?>
<videos>
<video id="1fb853907b9ca6add9ac">
<url>a.com</url>
<categories>A</categories>
<rating>100</rating>
<title>A</title>
<tags>A;a;AB</tags>
<duration>15</duration>
<thumbnail>http://i1.cdn2a.image.phncdn.com/m=eGcE8daaaa/videos/201011/03/148553/original/12.jpg</thumbnail>
</video>
<video id="d95ebc6a75c00d9926e7">
<url>http://ab.com</url>
<categories>A;B;An</categories>
<rating>100</rating>
<title>Sie spritzt ab</title>
<tags>a;b;as;d</tags>
<duration>65</duration>
<thumbnail>http://i0.cdn2a.image..phncdn.com/m=eGcE8daaaa/videos/201102/17/160998/original/12.jpg</thumbnail>
</video>
</videos>
before moving to logic, can you please put your js code at bottom of the page and put it in a separate js file if possible? This is a good practice. Now move on to algo ( I am assuming there is no incremental return from your service, i.e you will get 10000+ result at one shot )
xmlDoc.getElementsByTagName("video"); length of this array will give you total number of page, say length is x so total number of page is x/12
You can now create list of page numbers ( 1,2,....n). You can use LI tag or other to dynamically create the list using javascript for loop. In the li put anchor tag for further js page change operation.
Now create an object array inside the for loop.
For first page take first 12 element and create 12 rows.
when page 2 or other is clicked you have to take the page number ( that you can get from the link text) and you have to calculate array index. ( remember for page 2 start index will be 12 and end index will be 23 and so on ) Now clear the existing rows and add the new elements. in short pageSize*( pageNum -1 ) ;
for table creation you can use any template engine (like Handlebar or other)

Internet Explorer 11 won't read "getElementById" for XML and returns null

I wrote a webpage (with HTML, CSS, and javascript) which loads information from an XML file to "fill in the blanks" in the elements on the page. Everything works perfectly unless I load the page in Internet Explorer (I'm using IE 11.0).
I've had a few problems and worked around a couple of them, but new problems keep popping up, so I think I just don't understand how IE deals with XML.
The error I'm getting is:
Unable to get property 'querySelectorAll' of undefined or null reference
when I use the code:
selectedBookNodeList = bookDataDocument.getElementById(bookId);
In the IE debugger it shows "selectedBookNodeList" as NULL, but the bookDataDocument is NOT null. Again, this works perfectly fine in Chrome and Firefox (here's a link: http://www.pattmayne.com/stories2/).
Why is it NULL in IE11, but it works fine in the other browsers??
Here is all the code:
var bookPage;
var bookDataDocument;
var XMLConnection;
var bookDataRootNode;
var selectedBookNode;
var bookDescription;
var bookDescription2;
var bookDescription3;
var bookImage;
var bookTitle;
var paperbackLink;
var ebookLink;
function setupXML()
{
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
XMLConnection=new XMLHttpRequest();
}
else
{// code for IE6, IE5
XMLConnection=new ActiveXObject("Microsoft.XMLHTTP");
}
XMLConnection.open("GET", "novels/book_data.xml", false);
XMLConnection.send(null);
bookDataDocument = XMLConnection.responseXML;
}
function setBook(bookId)
{
selectedBookNodeList = bookDataDocument.getElementById(bookId);
bookTitle = selectedBookNodeList.querySelectorAll("title").item(0).childNodes[0].nodeValue;
bookDescription = selectedBookNodeList.querySelectorAll("description").item(0).childNodes[0].nodeValue;
bookDescription2 = selectedBookNodeList.querySelectorAll("description2").item(0).childNodes[0].nodeValue;
bookDescription3 = selectedBookNodeList.querySelectorAll("description3").item(0).childNodes[0].nodeValue;
ebookLink = selectedBookNodeList.querySelectorAll("ebookLink").item(0).childNodes[0].nodeValue;
paperbackLink = selectedBookNodeList.querySelectorAll("paperbackLink").item(0).childNodes[0].nodeValue;
bookImage = selectedBookNodeList.querySelectorAll("coverImage").item(0).childNodes[0].nodeValue;
bookPage = document.getElementById("storiesWindow").contentWindow.document;
bookPage.getElementById("bookTitle").innerHTML = bookTitle;
bookPage.getElementById("description").innerHTML = bookDescription;
bookPage.getElementById("description2").innerHTML = bookDescription2;
bookPage.getElementById("description3").innerHTML = bookDescription3;
bookPage.getElementById("buyEbookLink").href = ebookLink;
bookPage.getElementById("buyPaperbackLink").href = paperbackLink;
bookPage.getElementById("coverImage").src=bookImage;
}
I'd really love a solution, but I'd love even more to understand the dynamics that I'm obviously not understanding. I want to use XML for other stuff in the future.
I solved it by skipping the "getElementById" statement altogether. Instead I queried for "book" and then used "getAttribute('id')" and wrote a function with a loop to compare the ids to the bookId that was sent to the original function.
Here's the fixed, working code:
function setBook(bookId)
{
listOfBooks = bookDataDocument.querySelectorAll("book");
selectedBook = listOfBooks.item(2);
getSelectedBook(bookId);
bookTitle = selectedBook.querySelectorAll("title").item(0).childNodes[0].nodeValue;
bookDescription = selectedBook.querySelectorAll("description").item(0).childNodes[0].nodeValue;
bookDescription2 = selectedBook.querySelectorAll("description2").item(0).childNodes[0].nodeValue;
bookDescription3 = selectedBook.querySelectorAll("description3").item(0).childNodes[0].nodeValue;
ebookLink = selectedBook.querySelectorAll("ebookLink").item(0).childNodes[0].nodeValue;
paperbackLink = selectedBook.querySelectorAll("paperbackLink").item(0).childNodes[0].nodeValue;
bookImage = selectedBook.querySelectorAll("coverImage").item(0).childNodes[0].nodeValue;
bookPage = document.getElementById("storiesWindow").contentWindow.document;
bookPage.getElementById("bookTitle").innerHTML = bookTitle;
bookPage.getElementById("description").innerHTML = bookDescription;
bookPage.getElementById("description2").innerHTML = bookDescription2;
bookPage.getElementById("description3").innerHTML = bookDescription3;
bookPage.getElementById("buyEbookLink").href = ebookLink;
bookPage.getElementById("buyPaperbackLink").href = paperbackLink;
bookPage.getElementById("coverImage").src=bookImage;
}
function getSelectedBook(bookId)
{
for (var i=0; i<listOfBooks.length; i++)
{
bookString = listOfBooks.item(i).getAttribute("id");
if (bookString == bookId)
selectedBook = listOfBooks.item(i);
}
}
function setupXML()
{
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
XMLConnection=new XMLHttpRequest();
}
else
{// code for IE6, IE5
XMLConnection=new ActiveXObject("Microsoft.XMLHTTP");
}
XMLConnection.open("GET", "novels/book_data.xml", false);
XMLConnection.send(null);
bookDataDocument = XMLConnection.responseXML;
}
Hi I know this is an old one but I came across the same issue yesterday with a client. The issue I found in this case was that the client had IE11 and Flash 11 but my PC had IE11 and Flash 14; I updated his flash and everything worked, sop looks like as Flash 11 was pre-IE11, there is some support issue within the DOM for the flash object.
Hope this helps someone else too :-)
Regards
Liam

changing id of div using jquery

EDIT 2: Problem solved. The jquery pluggin created a div. I was barking up the wrong tree.
Thanks for all your swift answers! long time reader of stackoverflow but first time i've posted a question!
EDIT: So the reason why I want to change the id is to change the rating of a rating bar(I use the jrating jquery pluggin). The pluggin uses the digits in the beginning of the id to set the initial rating. Now I want to use ajax when I load a new player and that new player has a new rating that I want to update. Is this enough context?
Im at a loss here. I want to change the id of a selected div but it doesnt work!
I does seem to change the div id because document.title has the correct id when I give it the id of the div I just changed. However When I open the source code of my webpage the id didnt change...
function changePlayer() {
xmlhttp = createXHR();
xmlhttp.onreadystatechange = function () {
document.title = "onreadystatechange";
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
document.title = "4 and 200 is ok!";
var xmlDocument = xmlhttp.responseXML;
var playerId = xmlDocument.getElementsByTagName("id")[0].childNodes[0].nodeValue;
var playerName = xmlDocument.getElementsByTagName("firstName")[0].childNodes[0].nodeValue;
var playerlastName = xmlDocument.getElementsByTagName("lastName")[0].childNodes[0].nodeValue;
var playerTeamId = xmlDocument.getElementsByTagName("teamId")[0].childNodes[0].nodeValue;
var playerPicUrl = xmlDocument.getElementsByTagName("mainPic")[0].childNodes[0].nodeValue;
var playerShooting = xmlDocument.getElementsByTagName("shooting")[0].childNodes[0].nodeValue;
document.getElementById("playerNameAndTeam").innerHTML = "<b>" + playerName + " " + playerlastName + "</b>" + "<br>" + playerTeamId;
document.getElementById("playerPicture").src = "img/players/" + playerPicUrl;
$("[id*='_shooting']").attr("id", playerShooting / 10 + "_shooting"); //attr("id", "5.1_shooting");
document.title = $("[id*='_shooting']").attr("id");
$("[id*='_shooting']").css("background-color", "blue");
$("[id*='playerNameA']").css("background-color", "blue");
}
}
xmlhttp.open("GET", "playerPageMVC/AJAX/getInfoPlayer.php", true);
xmlhttp.send();
}
function createXHR() {
if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari
return new XMLHttpRequest();
} else { // code for IE6, IE5
return new ActiveXObject("Microsoft.XMLHTTP");
}
}
Try with Native JS like replacing this line :
$("[id*='_shooting']").attr("id",playerShooting/10 + "_shooting");
By this one :
$("[id*='_shooting']")[0].id = playerShooting/10 + "_shooting";
Caution : If $("[id*='_shooting']") match many elements, only the first will be changed.
EDIT : If you want to keep jQuery technic, depends on your version, you can try using prop(...) instead of attr(...)
when I tried changing ID with a sample code using JQuery it worked. You can view example here. Just change the id attribute
You are suppose to check the id change by inspecting element not by checking the loaded source of the web page.
If you mean your:
$("[id*='_shooting']").attr("id", playerShooting / 10 + "_shooting");
You can check that id by simply doing these:
$("[id*='_shooting']").attr("id", playerShooting / 10 + "_shooting");
alert($("#"+ playerShooting / 10 + "_shooting").attr("id"));
By viewing the source, you only view the original source, not the DOM as it exists in a current state.

Categories