How to evaluate xml with namespaces in office add ins? - javascript

I'm trying to search for particular nodes in office xml. I'm using wgxpath for it. Here is my code. But every time empty result is returned. Probably wgxpath doesn't work with namespaces (although it accepts nsResolver as parameter)
Word.run(function (ctx) {
var xml = ctx.document.body.getOoxml();
ctx.sync().then(function () {
try {
var parser = new DOMParser();
var doc = parser.parseFromString(xml, "text/xml");
var win = { 'document': doc };
wgxpath.install(win);
var nsResolver = doc.createNSResolver(doc.ownerDocument == null ? doc.documentElement : doc.ownerDocument.documentElement);
var result = doc.evaluate("/pkg:package/pkg:part/pkg:xmlData/w:styles/w:docDefaults/w:pPrDefault/w:pPr/w:spacing", doc, nsResolver, win.XPathResult.ANY_TYPE, null);
var items = [];
try {
var item = result.iterateNext();
while (item) {
items.push(item);
item = result.iterateNext();
}
}
catch (e) {
reject(e);
}
resolve(items);
});
});
I've also tried another example with simple xml:
var parser = new DOMParser();
var test = "<pkg:count xmlns:pkg='http://schemas.microsoft.com/office/2006/xmlPackage'><pkg:a>1</pkg:a></pkg:count>";
var doc = parser.parseFromString(test, "text/xml");
var win = { 'document': doc };
wgxpath.install(win);
var nsResolver = function(prefix) {
var ns = {
'pkg': 'http://schemas.microsoft.com/office/2006/xmlPackage'
};
return ns[prefix] || null;
}
var result = doc.evaluate('/pkg:count/pkg:a', doc, nsResolver, win.XPathResult.ANY_TYPE, null);
Result is the same: with prefixes empty result is returned, but if I remove prefixes, evaluation works.
How can I evaluate xml with namespaces in office add ins? Any other solution? I've tried to use ActiveXObject("Microsoft.XMLDOM"), but get "Can't create object" exception.

The built in XML parsing methods do support namespaces, but not xpath.
E.g. Document.getElementsByTagNameNS

Related

Check if 2 XML documents are identical with javascript

I have 2 xml documents stored which I get from an AJAX post request and I would like to check if they are the same. Obviously xml1 == xml2 is not working. Is there another way that I could make this work?
Try this. It parses the XML document using the method in this question and compares the two using isEqualNode.
function parseXMLString(xmlString) {
var xmlDoc;
if (window.DOMParser) {
var parser = new DOMParser();
xmlDoc = parser.parseFromString(xmlString, "text/xml");
} else // Internet Explorer
{
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
xmlDoc.loadXML(xmlString);
}
return xmlDoc;
}
var xmlObj1 = parseXMLString('<hello>world</hello>');
var xmlObj2 = parseXMLString('<hello>world</hello>');
var xmlObj3 = parseXMLString('<hello>world2</hello>');
var xmlObj4 = parseXMLString('<hello2>world</hello2>');
console.log(xmlObj1.isEqualNode(xmlObj2));
console.log(xmlObj1.isEqualNode(xmlObj3));
console.log(xmlObj1.isEqualNode(xmlObj4));
If you're using jQuery, you can parse the XML document using parseXML().

JScript to Javascript Conversion

The code below is a web service call to ICEPortal which is in JScript.NET format. Currently Iceportal doesn't have a webservice call using javascript. Has anybody done this using javascript? I need your help to convert the code below to javascript format.
// JScript.NET
var h:ICEPortal.ICEWebService = new ICEPortal.ICEWebService();
var myHeader:ICEPortal.ICEAuthHeader = new ICEPortal.ICEAuthHeader();
myHeader.Username = "distrib#distrib.com";
myHeader.Password = "password";
h.ICEAuthHeaderValue = myHeader;
var brochure:ICEPortal.Brochure;
var ErrorMsg;
var result = h.GetBrochure("MyMappedID", ErrorMsg, brochure);
I think you just need to remove the type definitions (in bold below):
var myHeader :ICEPortal.ICEAuthHeader = new ICEPortal.ICEAuthHeader();)
No idea what the ICEPortal classes are, but if they are available to your Javascript in the global namespace, the following should work. I've added these stubs in for the ICEPortal to test and it works fine for me in Chrome.
You'll obviously want to remove the stubs.
// stubbing out ICEPortal(s)
ICEPortal = {};
ICEPortal.ICEWebService = function() { return true; };
ICEPortal.ICEAuthHeader = function() { return true; };
ICEPortal.ICEWebService.prototype.GetBrochure = function() { return true; };
// end stubbing ICEPortal(s)
var h = new ICEPortal.ICEWebService();
var myHeader = new ICEPortal.ICEAuthHeader();
myHeader.Username = "distrib#distrib.com";
myHeader.Password = "password";
h.ICEAuthHeaderValue = myHeader;
var brochure;
var ErrorMsg;
var result = h.GetBrochure("MyMappedID", ErrorMsg, brochure);

Error with XPath in a parsed XML document (WrongDocumentError)

I'm creating a Firefox for Android extension and I have a problem with a XML document retrieved from a XMLHttpRequest: I can't find a way to select a node. The better solution I found is this, but I got this error when selecting with xpath on the document:
WrongDocumentError: Node cannot be used in a document other than the one in which it was created
This is my code:
var parser = Cc["#mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser);
var parsedXml = parser.parseFromString(xmlhttp.responseText, "text/xml");
var xpathExpression = "//td[contains(.,'Raw text')]/../td[2]/pre";
var res = window.content.document.evaluate(xpathExpression, parsedXml, null, window.XPathResult.STRING_TYPE , null);
If I replace the "evaluate" with the next line:
var res = parsedXml.selectSingleNode(xpathExpression);
Then I get the following error:
[JavaScript Error: "parsedXml.selectSingleNode is not a function"
{file: "resource://gre/modules/addons/XPIProvider.jsm ->
jar:file:///data/data/org.mozilla.fennec/files/mozilla/ggz9zzjr.default/extensions/qrReader#qrReader.xpi!/bootstrap.js"
line: 61}]
Well, the name of the exception, WrongDocumentErrort gave it away. You're trying to call .evaluate() on a DOM (Document) that does not belong to the same Document .evaluate() is bound to.
The nsIDOMParser will actually return a new XMLDocument that has an .evaluate() itself, which you'll have to use.
var parser = Cc["#mozilla.org/xmlextras/domparser;1"].
createInstance(Ci.nsIDOMParser);
var parsedDoc = parser.parseFromString(
'<?xml version="1.0"?>\n<doc><elem>Raw text</elem></doc>',
"text/xml");
var xpathExpression = "//elem[contains(.,'Raw text')]";
var res = parsedDoc.evaluate(
xpathExpression,
parsedDoc,
null,
XPathResult.STRING_TYPE,
null);
console.log(res, res.stringValue);
Instead using nsIDOMParser, since your content seems to be originating from XHR anyway, and seems to be (X)HTML (indicated by your expression), it might be better to use XHR.responseType = "document" instead, which will parse a DOM from the response using the HTML parser.
var req = new XMLHttpRequest();
req.onload = function() {
var doc = req.response;
var h1 = doc.evaluate("//h1", doc, null, XPathResult.STRING_TYPE, null);
console.log(h1.stringValue);
// Alternative in some cases
h1 = doc.querySelector("h1");
console.log(h1.textContent);
};
req.open("GET", "http://example.org/");
req.responseType = "document"; // Parse as text/html
req.send();
parseFromString returns a document object. selectSingleNode is not a document function. Can't you select a node using the standard document.getElementsByClassname, document.getElementById, or document.querySelector?
try
var window = parsedXml.ownerDocument.defaultView;
var res = window.content.document.evaluate(xpathExpression, parsedXml, null, window.XPathResult.STRING_TYPE , null);

How to use getComputedStyle with DOMParser produced document (no defaultView or window objects)?

I have this code (simplified):
var s = '<div>html...</div>';
var parser = new DOMParser();
var doc = parser.parseFromString(s, 'text/html');
The resulting document object does not have a defaultView nor a window properties, so is there a way to call getComputedStyle() ?
To explain more: I use code like this in a Firefox extension that performs batch DOM manipulation on HTML files and serializes then writes the modified documents back to disk.
As pointed out by Mike, there is a hiddenDOMWindow, so I adapted his code to something like this:
const { Services } = Cu.import("resource://gre/modules/Services.jsm");
var s = '<div style="color:red;font-family:Tahoma">html...</div>';
var parser = new DOMParser();
var doc = parser.parseFromString(s, 'text/html');
var div = doc.querySelector("div");
var win = Services.appShell.hiddenDOMWindow;
var div2 = win.document.importNode(div, true);
var style = win.getComputedStyle(div2);
alert( style.getPropertyValue('color') ); //alerts rgb(255, 0, 0) which is correct!
Thanks Mike, I never knew there was a hiddenDOMWindow.
This should work from either content or an extension:
var s = '<div>html...</div>';
var parser = new DOMParser();
var doc = parser.parseFromString(s, 'text/html');
var div = doc.querySelector("div");
var style = window.getComputedStyle(div);
If you don't have access to a window e.g. from an extension then you could do it this way:
const { Services } = Cu.import("resource://gre/modules/Services.jsm");
var s = '<div>html...</div>';
var parser = new DOMParser();
var doc = parser.parseFromString(s, 'text/html');
var div = doc.querySelector("div");
var win = Services.appShell.hiddenDOMWindow;
var style = win.getComputedStyle(div);

Is there a javascript function that takes a string as input and parse that string asif it is HTML and return me the according element?

Is there a javascript function that takes a string as input and parse that string asif it is HTML and return me the according element?
example: F("<div id='outer'><div id='inner'><span hello></span></div></div>")
will return me a div HTMLElement that have a child div which in turn has a span child.
No there is no such function. But you can use jQuery $("<div id='outer'><div id='inner'><span hello></span></div></div>") which will do what you want.
Here is a very simple plain javascript solution :
http://jsfiddle.net/7HdJc/1/
function returnTheNodes(htmlStr)
{
var myCont = document.createElement('DIV'); // create a div element
myCont.innerHTML = htmlStr; // create its children with the string
return myCont.childNodes; // return the children elements created :)
}
var newElems = returnTheNodes("<div id='outer'><div id='inner'><span hello></span></div></div>");
for(var i = 0; i < newElems.length ; i++ )
{
alert(newElems[i].id); // newElems[0] has the first DIV
}
And what about DOMParser?
Here is an example:
var str = '<div id="outer"><div id="inner"><span> hello</span></div></div>';
function parseStringToDOMElement (str)
{
var xmlDoc = null;
if (window.DOMParser)
{
var parser = new DOMParser ();
xmlDoc = parser.parseFromString (str, "text/xml");
}
else if (window.ActiveXObject)
{
xmlDoc = new ActiveXObject ("Microsoft.XMLDOM");
xmlDoc.async = false;
xmlDoc.loadXML (str);
}
return xmlDoc.firstChild;
}
var node=parseStringToDOMElement(str);
console.log(node);
I hope it will be helpfull

Categories

Resources