parsing xml in javascript - javascript

I need to create custom objects based on an XML input, the rule is that for every node if it has a direct child node is named EndNode and the text value of which is 1, then I create a leaf object. So for every node, I need to check the direct child with name EndNode and its value. It's not so easy with the DOM API and DOM selector (in this case I use Ext.DomQuery) doesn't have a way to select direct child of the root node... Below is my attempt for using DOM selector, I need to wrap the node around with another level of the node for the selector to work. But I can't just say new Node(), it silently fails.
I guess I have to walk through n.childNodes, but it is complicated to do it this way to check the rule I described above. Any solution?
Ext.each(node.childNodes, function(n){
if (n.nodeType == this.XML_NODE_ELEMENT) {
var tmp=new Node();
console.log('hi');
tmp.appendChild(n);
console.log(Ext.DomQuery.select(n.tagName+">EndNode", tmp));
}
}

I did an xml parser. It is quite easy with Dojo's library. Here ya are. When you're done with it though I recommend exporting the var to JSON and using it as cache.
dojo.require("dojox.xml.parser");
var parser = dojox.xml.parser;
function crules() {
this.rules = new Array();
this.xml = Object;
}
xml = '';
crules.prototype.load = function(file){
var xmlget = dojo.xhrGet({
url: file,
handleAs: "xml",
load: function(data){
xml = data;
},
error: function (error) {
console.error ('Error: ', error);
},
sync: true
}
);
this.xml = xml;
}
crules.prototype.buildout = function (){
var rules = this.xml.getElementsByTagName('ruleset');
//dojo.byId('jsloading').innerHTML = 'Loading Javascript';
for(var i=0; i<rules.length; i++){
//dojo.byId('jsloading').innerHTML += ' .';
r = new cruleset();
r.name = xtagvalue(rules[i],'name');
base = xtag(rules[i],'base');
textcustom = xtag(rules[i],'textcustom');
r.textcustomy = xtagvalue(textcustom[0],'y');
r.textcustomx = xtagvalue(textcustom[0],'x');
for(var j=0; j<base.length; j++){
r.bases[j] = new cbase();
r.bases[j].imgsrc = xtagvalue(base[j],'imgsrc');
r.bases[j].color = xtagvalue(base[j],'color');
r.bases[j].coloropts = new Array();
var copts = xtag(rules[i],'option');
for(var k=0; k<copts.length;k++){
var cc = new Object();
cc.color = xtagvalue(copts[k],'color');
cc.imgsrc = xtagvalue(copts[k],'imgsrc');
r.bases[j].coloropts.push(cc);
}
}
zones = xtag(rules[i],'zone');
for(var j=0; j<zones.length; j++){
z = new czone();
z.name =xtagvalue(zones[j],'name');
zoneconfigs = xtag(zones[j],'zoneconfig');
for(var n=0; n<zoneconfigs.length; n++){
zc = new czoneconfig();
zc.name = z.name;
zc.x1 =xtagvalue(zones[j],'x1');
zc.y1 =xtagvalue(zones[j],'y1');
zc.w =xtagvalue(zones[j],'w');
zc.h =xtagvalue(zones[j],'h');
hotspots = xtag(zoneconfigs[n],'hotspot');
for(var k=0; k<hotspots.length; k++){
h = new chotspot();
h.name = xtagvalue(hotspots[k],'name');
h.x =xtagvalue(hotspots[k],'x');
h.y =xtagvalue(hotspots[k],'y');
h.nameyoffset = xtagvalue(hotspots[k],'nameyoffset');
h.accessoryonly = xtagvalue(hotspots[k],'accessoryonly');
if(h.accessoryonly == null){
h.accessoryonly = 0;
}
var showname = xtag(hotspots[k],'showname');
if(!isEmpty(showname)){
h.showname = xtagvalue(hotspots[k],'showname');
}
/*h.itemset =xtagvalue(hotspots[k],'itemset');*/
items = xtag(hotspots[k],'item');
if(items){
for(var l=0;l<items.length;l++){
t = new citem();
t.id = xtagvalue(items[l],'id');
h.items[h.items.length] = t;
}
}
zc.hotspots[zc.hotspots.length] = h;
}
z.zoneconfigs[z.zoneconfigs.length] = zc;
}
r.zones[r.zones.length] = z;
}
this.rules[this.rules.length] = r;
}
/*xmltext = parser.innerXML(xml);
dojo.byId('cwindow').innerHTML = xmltext;*/
}
function xtag(e,tag){
var n=null;
n = e.getElementsByTagName(tag);
if(n.length>=1){
return e.getElementsByTagName(tag);
}
else return null;
}
function xtagvalue(e,tag){
var n=null;
n = e.getElementsByTagName(tag);
if(n.length>=1){
//console.log(tag,'here',n[0],parser.textContent(n[0]));
return parser.textContent(n[0]);
}
else return null;
}

Related

Array doesent update values

I want my array to be updated as soon as I run the replace function. What actually happens is that all the elements of my array get deleted here is the code:
var Person = [];
var editPersonId = 0;
var Details = [];
function AddPerson() {
this.Details[0] = document.getElementById("fname").value;
this.Details[1] = document.getElementById("lname").value;
this.Details[2] = document.getElementById("age").value;
this.Details[3] = document.getElementById("mobil").value;
this.Details[4] = document.getElementById("adress").value;
Person.push(this.Details);
}
function Clear(){
document.getElementById("fname").value = "";
document.getElementById("lname").value = "";
document.getElementById("age").value ="";
document.getElementById("mobil").value = "";
document.getElementById("adress").value = "";
}
function ShowContacts(){
var testIt= document.getElementById("search").value;
var i=0, k=0, indx=[], msg;
for ( i=0; i < Person.length; i++)
{
for ( k=0; k<=4; k++)
{
if (Person[i][k] === testIt)
{
document.getElementById("newFname").value = Person[i][0];
document.getElementById("newLname").value = Person[i][1];
document.getElementById("newAge").value = Person[i][2];
document.getElementById("newMobil").value = Person[i][3];
document.getElementById("newAdress").value = Person[i][4];
console.log(1);
editPersonId = i;
break;
}
}
}
}
function Replace(){
Person[editPersonId][0] = document.getElementById("newFname").value;
Person[editPersonId][1] = document.getElementById("newLname").value;
Person[editPersonId][2] = document.getElementById("newAge").value;
Person[editPersonId][3] = document.getElementById("newMobil").value;
Person[editPersonId][4] = document.getElementById("newAdress").value;
}
function Run(){
this.AddPerson();
this.Clear();
}
You override the contents of your Person insde of replace().
Person[editPersonId][0] = ...
While editPersonId is 0, means that the item you inserted in AddPerson will be overriden. And before replace(), you run clear(), which empties your inputs. So the elements don't get 'deleted', you replace them with an empty string.
You might wanna look into this article

Loop performance converting XML to JSON in JavaScript

I am encountering a performance issue trying to fill in a grid with some data from a webservice.
Thanks to the Timeline analyzer from Chrome, I have found the function wich is causing my performance issue. It's due to a loop to get all the data from an xml and converting it into a JSON.
I've tried different loop (each, for, while) expecting improvement but didn't find better than each.
Here is an example of the xml with one child (but in my case there can be 10000 childs):
<DockDistrSearchOutput>
<groupRecord>
<uniqueIdentifier><![CDATA[KP789281]]></uniqueIdentifier>
<supplierCode><![CDATA[10003]]></supplierCode>
<supplierDescription><![CDATA[GROSFILLEX]]></supplierDescription>
<supplierCommercialContractCode><![CDATA[CTCOM01]]></supplierCommercialContractCode>
<supplierCommercialContractDescription><![CDATA[STANDARD EN EURO]]></supplierCommercialContractDescription>
<supplierAddressChainCode><![CDATA[1]]></supplierAddressChainCode>
<supplierAddressChainDescription><![CDATA[FIL1]]></supplierAddressChainDescription>
<articleCode><![CDATA[13A42001]]></articleCode>
<articleDescription><![CDATA[Banane]]></articleDescription>
<logisticVariantCode><![CDATA[2]]></logisticVariantCode>
<logisticVariantDescription><![CDATA[VL0 BANANE C G100]]></logisticVariantDescription>
<weightFactor><![CDATA[0]]></weightFactor>
<purchasePricePerKilo><![CDATA[13]]></purchasePricePerKilo>
<amount><![CDATA[0]]></amount>
<startDate><![CDATA[2016-07-29]]></startDate>
<endDate><![CDATA[2016-07-31]]></endDate>
<crossDockDiscount />
<crossDockMargin />
<extraMargin><![CDATA[3]]></extraMargin>
<listPrice />
<costPriceRD />
<oldSupplierCode><![CDATA[10003]]></oldSupplierCode>
<oldSupplierCommercialContractCode><![CDATA[CTCOM01]]></oldSupplierCommercialContractCode>
<oldSupplierAddressChainCode><![CDATA[1]]></oldSupplierAddressChainCode>
<oldArticleCode><![CDATA[13A42001]]></oldArticleCode>
<oldLogisticVariantCode><![CDATA[2]]></oldLogisticVariantCode>
<oldStartDate><![CDATA[2016-07-29]]></oldStartDate>
<oldEndDate><![CDATA[2016-07-31]]></oldEndDate>
</groupRecord>
</DockDistrSearchOutput>
And here is the loop used to get the data (15900ms for my test case) :
function getDataFromXml(xml){
var data = [];
$(xml).children().each( function (index) {
uniqueNumber++;
var recStatus = ORIGINAL;
if(this.getAttribute("recordState")!=null){
recStatus = this.getAttribute("recordState");
}
this.setAttribute("recordState", recStatus);
this.setAttribute("lineNumber", uniqueNumber);
var record = [];
if(this.getAttribute("checkedLine") == "true"){
record["checkedLine"] = true;
}else
record["checkedLine"] = false;
// Build the array by reading XML Tagname/value
record["id"] = "ID"+uniqueNumber;
$(this).children().each(function () {
record[this.tagName] = this.text;
});
record["recordState"] = recStatus;
record["rowXML"] = this;
data.push(record);
record = null;
recStatus = null;
});
return data;
}
Here are other try to get the data faster:
function getDataFromXml(xml){
var data = [];
$(xml).children().each( function (index) {
uniqueNumber++;
var recStatus = ORIGINAL;
if(this.getAttribute("recordState")!=null){
recStatus = this.getAttribute("recordState");
}
this.setAttribute("recordState", recStatus);
this.setAttribute("lineNumber", uniqueNumber);
var record = [];
/* First try
var a = $(this).children();
var l = a.length;
while(l--){
record[a[l].tagName] = a[l].text;
}*/
//Second try
var tmp = "{", cur = null;
for(var i =0, ln=this.childElementCount; i<ln;++i)
{
cur = this.children[i];
tmp += '"'+cur.tagName+'":"'+cur.text.replace('"', '')+'",';
}
tmp +='}';
tmp = tmp.replace(',}', '}');
record=JSON.parse(tmp);
if(this.getAttribute("checkedLine") == "true"){
record["checkedLine"] = true;
}else
record["checkedLine"] = false;
// Build the array by reading XML Tagname/value
record["id"] = "ID"+uniqueNumber;
record["recordState"] = recStatus;
record["rowXML"] = this;
data.push(record);
tmp = null;
cur = null;
record = null;
recStatus = null;
});
return data;
}
A try with only JavaScript (9600ms in my test case):
function getDataFromXml(xml){
var data = [];
var a = xml.getElementsByTagName("groupRecord");
var l = a.length;
while(l--){
uniqueNumber++;
var recStatus = ORIGINAL;
var groupRec = a[l];
if(groupRec.getAttribute("recordState")!=null){
recStatus = groupRec.getAttribute("recordState");
}
groupRec.setAttribute("recordState", recStatus);
groupRec.setAttribute("lineNumber", uniqueNumber);
var record = [];
var b = groupRec.childNodes;
var j = b.length;
while(j--){
record[b[j].tagName] = b[j].text;
}
if(groupRec.getAttribute("checkedLine") == "true"){
record["checkedLine"] = true;
}else
record["checkedLine"] = false;
// Build the array by reading XML Tagname/value
record["id"] = "ID"+uniqueNumber;
record["recordState"] = recStatus;
record["rowXML"] = groupRec;
data.push(record);
tmp = null;
cur = null;
record = null;
recStatus = null;
groupRec = null;
}
return data;
}
If someone has any advice to increase the performance of my loop?
Thanks in advance!
Edit: Thanks to Jaromanda X I have improved the performance by using only JavaScript.

JavaScript cannot find method a second time?

I'm attempting to build a poker game. The method in question is very simple, and it works when it runs the first time.
This part isn't perfect convention because I'm just using it to test my methods:
var $ = function (id) { return document.getElementById(id); };
var test = function() {
var deck = new POKER.Deck();
var hand = new POKER.Hand();
for (var i = 0; i < 7; i++){
hand.addCard(deck.dealCard());
}
hand.sortByRank();
for (var j = 0; j < 7; j++){
var img = document.createElement("img");
var card = hand.getCardAtIndex(j); //** <------- WORKS HERE**
img.src = card.getImage();
$("images").appendChild(img);
}
var testHand = new POKER.Hand();
testHand = hand.removePairs();
for (var k = 0; k < testHand.length; k++) {
var img2 = document.createElement("img");
var card2 = testHand.getCardAtIndex(k); // **<------FAILS HERE**
img2.src = card2.getImage();
$("handImg").appendChild(img2);
}
};
window.onload = function() {
test();
};
The first and second loop work, and the hand is displayed and everything. When it gets to the last loop, the debugger tells me "TypeError: testHand.getCardAtIndex is not a function"
I was attempting to test the removePairs method (to test for straights more easily), and when watching the variables in the debugger, testHand clearly gets populated correctly. The method seems to work just fine.
getCardAtIndex:
POKER.Hand.prototype.getCardAtIndex = function(index) {
return this.cards[index];
};
removePairs:
POKER.Hand.prototype.removePairs = function(){
var allCards = this.cards;
var tempCards = [];
var uniqueRanks = [];
var unique;
for(var i = 0; i < allCards.length; i++){
unique = true;
for(var j = 0; j < uniqueRanks.length; j++){
if(allCards[i].getRank() == uniqueRanks[j]){
unique = false;
break;
}
}
if(unique){
uniqueRanks.push(allCards[i].getRank());
tempCards.push(allCards[i]);
}
}
return tempCards;
};
I'm completely perplexed.
var testHand = new POKER.Hand();
testHand = hand.removePairs();
hand.removePairs() returns an Array, not a Hand object.
That's why you don't have access to the getCardAtIndex method.
If cards is a public property you could do:
testHand.cards = hand.removePairs();
Or you can have a setter method:
testHand.setCards(hand.removePairs);

Exploit the built in XPath engine to query javaScript objects

NOTE: I am not looking for a way to query the HTML document itself. I want to create my own document from my javaScript object and pass it as root argument to the evaluate function.
Say I have the following script:
function Attribute(name, value) {
this.name;
this.value;
}
function Node(nodeName) {
this.nodeName = nodeName;
this.textContent = "";
this.childrenNodes = [];
this.attributes = [];
}
var root = new Node("root");
root.attributes.push(new Attribute("name", "treeRoot"));
var c1 = new Node("child");
c1.attributes.push(new Attribute("name", "child1"));
c1.textContent = "I'm the first child!";
var c2 = new Node("child");
c2.attributes.push(new Attribute("name", "child2"));
root.childrenNodes.push(c1);
root.childrenNodes.push(c2);
That represents the following simple XML:
<root name="treeRoot">
<child name="child1">
I'm the first child!
</child>
<child name="child2"/>
</root>
I would like to use the build in XPath engine to query this XML-like structure. Somthing like:
myDocument = createDocument(root);
myDocument.evaluate("/root/child[#name='child2']", myDocument, null, XPathResult.ANY_TYPE, null);
That would return an XPathResult of Node collection containing c1 Node.
How do I implement the createDocument function?
EDIT:
My goal is to be able to query javaScript objects. In Java I can create a Document object and use XPath to query it. I'm looking for something similar in javaScript.
You need a couple of functions here to convert your "DOM" implementation to a standard XML DOM - one to create the document and another to recursively create elements:
// create a document based on a Node instance
function toXmlDom(node) {
// create a document
var doc = document.implementation.createDocument('', '');
// convert the root node
var e = toXmlElement(doc, node);
// add root to document
doc.appendChild(e);
return doc;
}
// convert a Node and its children to an XML element
function toXmlElement(doc, node) {
// create an element
var e = doc.createElement(node.nodeName);
// set its attributes
for(var i = 0; i < node.attributes.length; i++) {
var attr = node.attributes[i];
e.setAttribute(attr.name, attr.value);
}
// set its text content
e.textContent = node.textContent;
// convert and add its child nodes
for(var i = 0; i < node.childrenNodes.length; i++) {
var childrenNode = node.childrenNodes[i];
var childNode = toXmlElement(doc, childrenNode);
e.appendChild(childNode);
}
return e;
}
// do the conversion
var myDocument = toXmlDom(root);
Working Example
console.clear();
function Attribute(name, value) {
this.name = name;
this.value = value;
}
function Node(nodeName) {
this.nodeName = nodeName;
this.textContent = "";
this.childrenNodes = [];
this.attributes = [];
}
function toXmlDom(node) {
// create a document
var doc = document.implementation.createDocument('', '');
// convert the root node
var e = toXmlElement(doc, node);
// add root to document
doc.appendChild(e);
return doc;
}
function toXmlElement(doc, node) {
// create an element
var e = doc.createElement(node.nodeName);
// set its attributes
for(var i = 0; i < node.attributes.length; i++) {
var attr = node.attributes[i];
e.setAttribute(attr.name, attr.value);
}
// set its text content
e.textContent = node.textContent;
// convert and add its child nodes
for(var i = 0; i < node.childrenNodes.length; i++) {
var childrenNode = node.childrenNodes[i];
var childNode = toXmlElement(doc, childrenNode);
e.appendChild(childNode);
}
return e;
}
var root = new Node("root");
root.attributes.push(new Attribute("name", "treeRoot"));
var c1 = new Node("child");
c1.attributes.push(new Attribute("name", "child1"));
c1.textContent = "I'm the first child!";
var c2 = new Node("child");
c2.attributes.push(new Attribute("name", "child2"));
root.childrenNodes.push(c1);
root.childrenNodes.push(c2);
var myDocument = toXmlDom(root);
// get the text of the first child - "I'm the first child!"
var result = myDocument.evaluate("/root/child[#name='child1']", myDocument, null, XPathResult.ANY_TYPE, null);
var thisNode = result.iterateNext();
while (thisNode) {
document.getElementById('result').innerHTML += thisNode.textContent + "<br/>";
thisNode = result.iterateNext();
}
document.getElementById('doctext').value = myDocument.documentElement.outerHTML;
<p><b>/root/child[#name='child1'].textContent:</b> <span id="result"></span></p>
<b>Document XML</b><br/>
<textarea id="doctext" cols="50" rows="10"></textarea>

Photoshop Javascript to get all layers in the active document

I'm sure it should be discussed before by Photoshop scripters. I write a solution as following. I think it's logically right, but the result is not correct. Anybody can help to check where's wrong in the code, or have ideas for this topic? I want to get all the layers in a document.
Code:
function getAllLayersInLayerSets(layerNodes) {
var retList = [];
for (var i=0; i<layerNodes.length; i++) {
if(layerNodes[i].layerSets.length > 0)
{
var tmp = getAllLayersInLayerSets(layerNodes[i].layerSets);
var j = (tmp == null) ? -1 : tmp.length-1;
while(tmp && j>=0)
{
retList.push(tmp[i]);
j--;
}
}
for(var layerIndex=0; layerIndex < layerNodes[i].artLayers.length; layerIndex++)
{
var layer=layerNodes[i].artLayers[layerIndex];
retList.push(layer);
}
}
return retList;
}
Many thanks for any help or discussion.
I know this is an old thread, but this might be useful for someone.
I was looking for a function that would get me all the ArtLayers in a Photoshop comp, including layers nested in groups. The above function was returning undefined, so I modified it and got it to work.
var doc = app.activeDocument;
var allLayers = [];
var allLayers = collectAllLayers(doc, allLayers);
function collectAllLayers (doc, allLayers){
for (var m = 0; m < doc.layers.length; m++){
var theLayer = doc.layers[m];
if (theLayer.typename === "ArtLayer"){
allLayers.push(theLayer);
}else{
collectAllLayers(theLayer, allLayers);
}
}
return allLayers;
}
Minor expansion on Ghoul Fool's post to only get all VISIBLE art layers in the active document. :P
// Get layers in a document
var sourceDocument = app.activeDocument;
var visibleLayers = [];
var visibleLayers = collectAllLayers(sourceDocument, visibleLayers);
// Print out total layers found
alert(visibleLayers.length);
// Recursively get all visible art layers in a given document
function collectAllLayers (parent, allLayers)
{
for (var m = 0; m < parent.layers.length; m++)
{
var currentLayer = parent.layers[m];
if (currentLayer.typename === "ArtLayer")
{
if(currentLayer.visible)
{
allLayers.push(currentLayer);
}
}
else
{
collectAllLayers(currentLayer, allLayers);
}
}
return allLayers;
}
To get all the layers (and sub layers) you have to have a recursive function
var allLayers = new Array();
var theLayers = collectAllLayers(app.activeDocument, 0);
function collectAllLayers (theParent, level)
{
for (var m = theParent.layers.length - 1; m >= 0; m--)
{
var theLayer = theParent.layers[m];
if (theLayer.typename != "ArtLayer")
{
allLayers.push(level + theLayer.name);
collectAllLayers(theLayer, level + 1)
}
}
}
function selectAllLayers() {
var desc29 = new ActionDescriptor();
var ref23 = new ActionReference();
ref23.putEnumerated(charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
desc29.putReference(charIDToTypeID('null'), ref23);
executeAction(stringIDToTypeID('selectAllLayers'), desc29, DialogModes.NO);
}

Categories