1

I would like to extend/derive from the XML Document returned by jQuery's $.parseXML() function, to add my own properties/functions. I am new to jQuery/JavaScript object inheritance. I have tried to read all over the web but am not "getting" it.

In, say, C# classes I could write something (kept simple) like this:

public class MyXmlDocument : XmlDocument
{
  public MyXmlDocument(string xmlText)
  {
    this.LoadXml(xmlText);
  }

  public string SomeVariable;
  ...

  public XmlNode FindCertainNode()
  {
    return this.SelectSingleNode("certain");
  }
  ...
}

MyXmlDocument xmlDoc = new MyXmlDocument(xmlText);
xmlDoc.AppendChild(...);  // XmlDocument method
XmlNode xmlNode = xmlDoc.FindCertainNode();  // MyXmlDocument method
etc.

I hesitate to show my jQuery/JavaScript attempt because I am quite at sea, but I know people like to see something, so please regard it as "some ideas I have been playing with":

// One approach
function XMLDoc(xmlText)
{
  var parseXML = function (xmlText)
  {
    //var parser = new DOMParser();
    //var xmlDoc = parser.parseFromString(xmlText, "text/xml");
    var xmlDoc = $.parseXML(xmlText);
    return xmlDoc;
  };

  var findCertainNode = function ()
  {
    return this.find('certain');
  }

  return parseXML(xmlText);
}

// Another approach
var XMLDoc = $.extend({}, $.parseXML.prototype, {
  findCertainNode: function () {
    this.find('certain');
  }
});

I am expecting to be able to access existing functionality for the XML document plus my own extensions, along the lines of:

var xmlDoc = new XMLDoc(xmlText);
var $xmlDoc = $(xmlDoc);
$xmlDoc.find('certain');  // jQuery method
$xmlDoc.findCertainNode();  // my additional method

I also know that I am unclear about whether my code should be returning plain JavaScript objects or jQuery ones. I am thinking jQuery ones, so that I can easily call for example jQuery's .find() etc.

It is important to me that the code should all be wrapped inside a single function/object or similar for editing/viewing, as both my attempts do.

If someone could show how they would implement the C# pattern I think that would answer my question, and I should be most grateful.

EDIT: Solution

I am marking @Karol's solution below (https://stackoverflow.com/a/42672481/489865) as the accepted one as he did the most work to answer my question as phrased.

However, I have come to realise that the object returned from $.parseXML()/DOMParser().parseFromString() is not some special "XML document", it's just an element, and as such has no special methods. It is not worth it to derive/inherit from it, and so encapsulation is adequate and simpler. My pattern looks like:

var XMLDoc = function (xmlText) {
  this._xmlDoc = $.parseXML(xmlText);
};

$.extend(XMLDoc.prototype, {
    doc: this._xmlDoc,
    find: function (selector) {
      return $(this._xmlDoc).find(selector);
    },
    findCertain: function () {
      return $(this._xmlDoc).find("certain");
    },
    ...
});

var xmlDoc = new XMLDoc(xmlText);
xmlDoc.find('something');
xmlDoc.findCertainNode();
Community
  • 1
  • 1
JonBrave
  • 4,045
  • 3
  • 38
  • 115
  • Inheriting from jQuery is a bad idea and will hardly work. You can however extend jQuery with your own methods, search the web for "jQuery plugin" – Bergi Mar 08 '17 at 13:05
  • You might read this: http://ejohn.org/blog/simple-class-instantiation/ and the answers to this: http://stackoverflow.com/questions/9057816/john-resigs-simple-class-instantiation-and-use-strict from Hubert. – Mark Schultheiss Mar 08 '17 at 23:23

2 Answers2

1

Try with:

var xmlDoc = new XMLDoc(xmlText);
$.extend( xmlDoc, {
  find: function(par){
          // your function
        }
});
NikNik
  • 2,191
  • 2
  • 15
  • 34
  • What is your definition of `XMLDoc`? If it does not derive from the object returned by `$.parseXML()` but encapsulates instead, I will have to write new methods for every existing method I want to access. I had hoped for a solution like my C# example, where I can call both my own methods & inherited ones off the new object? – JonBrave Mar 08 '17 at 15:35
1

Try to do sth like this:

function XMLDoc(xmlText) { //constructor
  this._xmlDoc = $.parseXML(xmlText); //'_' is JS convention for private fields
}
XMLDoc.prototype = {
  findCertainNode: function() {
    return $(this._xmlDoc).find('certain');
  }
  /* other methods here */
}

var myXML = new XMLDoc('<a><certain /></a>')
myXML.findCertainNode(); //[<certain />]

Or the same with ES6 syntax:

class XMLDoc {
  constructor(xmlText) {
    this._xmlDoc = $.parseXML(xmlText);
  }
  findCertainNode() {
    return $(this._xmlDoc).find('certain');
  }
}

var myXML = new XMLDoc('<a><certain /></a>')
myXML.findCertainNode(); //[<certain />]

I think the real inheritance from jQuery is impossible, but if you really want to have an ability to use it in C# way, you can do sth like this:

Object.keys(Object.getPrototypeOf($())).forEach(function(key){
  XMLDoc.prototype[key] = function() {
    return $(this._xmlDoc)[key].apply(null, arguments);
  }
})

Or in ES6:

Object.keys(Object.getPrototypeOf($())).forEach(key => {
  XMLDoc.prototype[key] = () => {
    return $(this._xmlDoc)[key](...arguments);
  }
})

Then you can fire all jQuery methods as they were inherited.

And if you'd like to overload some of them, remember to do this overloading after the code above.

Karol Selak
  • 4,248
  • 6
  • 35
  • 65
  • In your first solution, if I have 50 methods to add I end with 50 separate `XMLDoc.prototype...` statements, outside the `XMLDoc` declaration. This is horrible for my folding editor. That is why I wanted the solution to "wrap" all the new methods inside one function (`XMLDoc`) if possible? – JonBrave Mar 08 '17 at 15:27
  • In both solutions `XMLDoc` does not derive from the XML object returned by `$.parseXML()`, it encapsulates. That means I have to write new methods for every existing method (e.g. `.find()`) I want to access. I had hoped for a solution like my C# example, where I can call both my own methods & inherited ones off the new object? – JonBrave Mar 08 '17 at 15:30