How do you find the (string) length of the start or end tag?

I am trying to write jQuery or a pure Javascript function (preferring a more readable solution) that can read the length of the source tag or end tag in an HTML document.

For instance,

<p>Hello.</p> 

will return 3 and 4 for the initial and final tag lengths. Adding Attributes

 <span class="red">Warning!</span> 

will return 18 and 7 for the initial and final tag lengths. Finally,

 <img src="foobar.png"/> 

will return 23 and 0 (or -1) for the length of the start and end of the tag.

I am looking for a canonical solution guaranteed to work in accordance with the requirements, so I try to use DOM methods, rather than manual manipulations with the text. For example, I would like the solution to work even in such strange cases as

 <p>spaces infiltrating the ending tag</ p > 

and

 <img alt="unended singleton tags" src="foobar.png"> 

etc. That is, I hope that as long as we use the correct DOM methods, we should be able to find the number of characters between < and > no matter how strange things turn out, even

 <div data-tag="<div>">HTML-like strings within attributes</div> 

I looked through the jQuery API (especially the Manipulation section, including the DOM subsections of Insertion and General Attributes), but I don't see anything that could help.

Currently, the best idea I got, given the node element, is

 lengthOfEndTag = node.tagName.length + 3; lengthOfStartTag = node.outerHTML.length - node.innerHTML.length - lengthOfEndTag; 

but of course I don’t want to make such an assumption for the final tag.

(Finally, I am familiar with the & mdash regular expressions, but try to avoid them, if at all possible.)


EDIT

@Pointy and @squint helped me understand that it's impossible to see </ p > , for example, because HTML is discarded after the DOM is created. It's great. The corrected goal is to find the length of the start and end tags that will be displayed in outerHTML .

+4
source share
2 answers

This answer helped me understand what @Pointy and @squint were trying to say.

The following solution works for me:

 $.fn.lengthOfStartTag = function () { var node = this[0]; if (!node || node.nodeType != 1) { $.error("Called $.fn.lengthOfStartTag on non-element node."); } if (!$(node).is(":empty")) { return node.outerHTML.indexOf(node.innerHTML); } return node.outerHTML.length; } $.fn.lengthOfEndTag = function () { var node = this[0]; if (!node || node.nodeType != 1) { $.error("Called $.fn.lengthOfEndTag on non-element node."); } if (!$(node).is(":empty")) { var indexOfInnerHTML = node.outerHTML.indexOf(node.innerHTML); return node.outerHTML.length - (indexOfInnerHTML + node.innerHTML.length); } return -1; } 

JsFiddle example here.

0
source

An alternative way to do this could be to use serializeToString XMLSerializer in a cloned copy of a node (with a set of identifiers) to avoid parsing innerHTML and then split it into "><"

 var tags = (function () { var x = new XMLSerializer(); // scope this so it doesn't need to be remade return function tags(elm) { var s, a, id, n, o = {open: null, close: null}; // spell stuff with var if (elm.nodeType !== 1) throw new TypeError('Expected HTMLElement'); n = elm.cloneNode(); // clone to get rid of innerHTML id = elm.getAttribute('id'); // re-apply id for clone if (id !== null) n.setAttribute('id', id); // if it was set s = x.serializeToString(n); // serialise a = s.split('><'); if (a.length > 1) { // has close tag o.close = '<' + a.pop(); o.open = a.join('><') + '>'; // join "just in case" } else o.open = a[0]; // no close tag return o; } }()); // self invoke to init 

After starting this application, you can access the .length of the open and close properties

 tags(document.body); // {open: "<body class="question-page">", close: "</body>"} 

What if the attribute value has >< in it? XMLSerializer avoids this until &gt;&lt; , so it will not change the value of .split .
What about tags? close will be null .

+1
source

Source: https://habr.com/ru/post/1479012/


All Articles