Obtain individual body tag elements

2

I have the following code:

function obtener(){

  var contador = 1;

  $("body").each(function(){
  
    console.log(contador + " " + $(this).text() + "\n");
    console.log("----------------------------------\n");
  
    contador++;
  
  });

}
<html>

<head>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>

<body>

  <ul class="level-1">
    <li class="item-i">I</li>
    <li class="item-ii">II
      <ul class="level-2">
        <li class="item-a">A</li>
        <li class="item-b">B
          <ul class="level-3">
            <li class="item-1">1</li>
            <li class="item-2">2</li>
            <li class="item-3">3</li>
          </ul>
        </li>
        <li class="item-c">C</li>
      </ul>
    </li>
    <li class="item-iii">III</li>
  </ul>

<input type="submit" onclick="obtener();" value="Obtener">

</body>

</html>

The code first shows an organized list, with certain texts and bullets, in short, the one in this example is only demonstrative.

What I intend to do is obtain the text of each of the elements contained within the label individually.

I tried the .each function of , as follows:

$("body").each(function(){

    console.log(contador + " " + $(this).text() + "\n");
    console.log("----------------------------------\n");

});

But, when the console.log message is printed, everything is displayed as a single text, that is, instead of being printed like this:

I
---------
II
---------
A
---------
B
---------

It is printing like this:

I
II

    A
    B

        1
        2
        3
---------------------

I have not found documentation about it, other than jQuery and the management of the .each function, but I do not understand why it prints everything as a single text, since it "runs through" each of the elements contained in the selector.

    
asked by Ivan Botero 30.07.2017 в 18:32
source

2 answers

5

It seems that what you want is to read all the independent text nodes that are on a page, without needing them to be grouped; for this you can use pure JavaScript and TreeWalker . The TreeWalker object represents the nodes of a document subtree and its position.

Then what you could do is create a TreeWalker and go through all the nodes of the body staying only with the text nodes. That is something that can be defined when you create TreeWalker with createTreeWalker :

treeWalker = document.createTreeWalker(raiz, queMostrar, filtro, expansionEntidadferencia);

where:

  • raiz is the node that will be used as the origin to create the TreeWalker (only the subtree will be scanned from that element), in your case you want it to be the body .
  • queMostrar is an optional parameter to indicate what types of nodes you want to obtain. You can have different values that will show some values or others, in your case you want to show only text nodes so you should use NodeFilter.SHOW_TEXT . You can see the complete list in the link above.
  • filtro is an optional parameter to pass a filter to the nodes found by queMostrar .
  • expansionEntidadReferencia is an optional Boolean parameter that indicates that if a EntityReference is discarded then all the subtree that leaves it will also be discarded at the same time.

A problem to use TreeWalker is not supported by all browsers. It's not available for versions of Internet Explorer prior to 9, and support is basic for Edge ... but as you say you want it for a Chrome plugin, you should have no problem.

Here is an example with your code:

function obtener(){

  var raiz = document.querySelector("ul.level-1");
  var queMostrar = NodeFilter.SHOW_TEXT;
  var filtro = { acceptNode: function(node) { 
    if ( !/^\s*$/.test(node.data) ) { 
      return NodeFilter.FILTER_ACCEPT; 
    } } };
  var expansion = false;
  
  var treeWalker = document.createTreeWalker(raiz, queMostrar, filtro, expansion);

  var nodos = [];

  while(treeWalker.nextNode()) 
    nodos.push(treeWalker.currentNode.data.trim());
    
  console.log(nodos);
  return nodos;
}
<body>
  <ul class="level-1">
    <li class="item-i">I</li>
    <li class="item-ii">II
      <ul class="level-2">
        <li class="item-a">A</li>
        <li class="item-b">B
          <ul class="level-3">
            <li class="item-1">1</li>
            <li class="item-2">2</li>
            <li class="item-3">3</li>
          </ul>
        </li>
        <li class="item-c">C</li>
      </ul>
    </li>
    <li class="item-iii">III</li>
  </ul>
  <input type="submit" onclick="obtener();" value="Obtener">
</body>

Note: the filter is to prevent "false positives" from being inserted into the array. What it does is that it does not accept the node if it is only made up of separators and blank spaces. It's not mine, I've taken it from this MDN page . p>     

answered by 30.07.2017 / 23:44
source
1

To scroll through all the elements within the body tag you need to use the universal selector * such that:

function obtener() {
  $('body *').each(function(indice, elementoHTML) {
    console.log(indice + " " + $(elementoHTML).text() + "\n");
    console.log("----------------------------------\n");
  });
}
<html>

<head>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>

<body>

  <ul class="level-1">
    <li class="item-i">I</li>
    <li class="item-ii">II
      <ul class="level-2">
        <li class="item-a">A</li>
        <li class="item-b">B
          <ul class="level-3">
            <li class="item-1">1</li>
            <li class="item-2">2</li>
            <li class="item-3">3</li>
          </ul>
        </li>
        <li class="item-c">C</li>
      </ul>
    </li>
    <li class="item-iii">III</li>
  </ul>

  <input type="submit" onclick="obtener();" value="Obtener">

</body>

</html>

Notice, that it is not necessary to handle a counter outside the function each , since it includes the index as the first parameter, and the element that is treated as the second.

    
answered by 30.07.2017 в 20:38