admin管理员组

文章数量:1352233

I'm working on writing a bookmarklet to enhance my workflow at work. Part of my job is obtaining the correct information to be placed into an email. I love JavaScript and jQuery, so I'm working on a way to make my job easier using this library.

I'm targeting a website that has particularly odd markup. I need to capture the text after a matched label tag, and before the next label tag. This is all, oddly enough, inside a P tag. I have no clue why the website's developer decided to use label tags either... I am unable to modify the markup, so that's not an option. I've searched all across the web and haven't been able to find a working technique for my specific situation.

I created a jsFiddle to demonstrate what I'm trying to do using the same kind of markup and CSS. I have no problem accessing the label, and I've used a few different methods to do so (in the fiddle, mented out) but I am still unable to properly "capture" the text in between the two label tags. The text will end up being placed into an alert so I can quickly copy it. I've tried using .nextUntil but have had no luck with it.

Basically it would be something like this:

<label>item 1</label> Content to capture
<br><br>
<label>item 2</label> Don't capture this...

I fear the reason my attempts aren't working is because (I think) nextUntil() tries to find the next object using the initial selector, so it's looking for the next label, rather than the text in between. I've tried using $('selector').parent().nextUntil('label') which also hasn't worked.


Here's the working example:

$(document).ready(function(){
  //$('p label:eq(0)')afterUntil('<br>').css('color', 'red');
  //$('p').find($('label:contains("item 1")')).nextUntil("<label>").css('color', 'red');
  $('p label:contains("item 1")').parent().nextUntil('label').css('color','red');
});
label {
  display:inline-block;    
  width:25%;
  font-weight:bold;
}
p {
  font-family:arial;
}
<script src=".1.1/jquery.min.js"></script>

<p>
  <label>item 1</label> Capture me!<br><br>
  <label>item 2</label> Don't capture me
</p>

I'm working on writing a bookmarklet to enhance my workflow at work. Part of my job is obtaining the correct information to be placed into an email. I love JavaScript and jQuery, so I'm working on a way to make my job easier using this library.

I'm targeting a website that has particularly odd markup. I need to capture the text after a matched label tag, and before the next label tag. This is all, oddly enough, inside a P tag. I have no clue why the website's developer decided to use label tags either... I am unable to modify the markup, so that's not an option. I've searched all across the web and haven't been able to find a working technique for my specific situation.

I created a jsFiddle to demonstrate what I'm trying to do using the same kind of markup and CSS. I have no problem accessing the label, and I've used a few different methods to do so (in the fiddle, mented out) but I am still unable to properly "capture" the text in between the two label tags. The text will end up being placed into an alert so I can quickly copy it. I've tried using .nextUntil but have had no luck with it.

Basically it would be something like this:

<label>item 1</label> Content to capture
<br><br>
<label>item 2</label> Don't capture this...

I fear the reason my attempts aren't working is because (I think) nextUntil() tries to find the next object using the initial selector, so it's looking for the next label, rather than the text in between. I've tried using $('selector').parent().nextUntil('label') which also hasn't worked.


Here's the working example:

$(document).ready(function(){
  //$('p label:eq(0)')afterUntil('<br>').css('color', 'red');
  //$('p').find($('label:contains("item 1")')).nextUntil("<label>").css('color', 'red');
  $('p label:contains("item 1")').parent().nextUntil('label').css('color','red');
});
label {
  display:inline-block;    
  width:25%;
  font-weight:bold;
}
p {
  font-family:arial;
}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<p>
  <label>item 1</label> Capture me!<br><br>
  <label>item 2</label> Don't capture me
</p>
(fiddle: http://jsfiddle/1c2LpzrL/1/)

Share Improve this question edited May 8, 2015 at 19:51 myfunkyside 3,9501 gold badge20 silver badges32 bronze badges asked May 8, 2015 at 18:22 BenderhuneBenderhune 331 silver badge5 bronze badges 1
  • 1 Wele to SO! Please post your code in the fiddle and in the question. If for some reason jsfiddle is down or your code disappears or whatever, your question is depleted of valuable resources. – Kyll Commented May 8, 2015 at 18:28
Add a ment  | 

6 Answers 6

Reset to default 3

You can just treat the HTML inside of the <p> tag as a string and then get the substring between the </label> and the first <br>:

var totalText = $("p").html();
//determine start-pos and end-pos of desired substring, and then get it
var startPos = totalText.indexOf("</label>") + "</label>".length;
var endPos = totalText.indexOf("<br");
var targetText = totalText.substring(startPos,endPos).trim();

(fiddle: http://jsfiddle/3uw8ux9t/3/)

  1. startPos finds the position of the first "</label>" and then adds the length of "</label>" to that.
  2. endPos finds the position of the first "<br" (I left the closing > out because officially it's spelled <br />, my way allows for both ways of spelling).
  3. targetText finally takes the substring from the startPos to the endPos.
    (.trim() removes any empty spaces from the start and end of your new string)

    • console.log(targetText) gives:

      Capture me!


UPDATE:

After your ment, I rewrote my script to acmodate for your specified needs:

$(document).ready(function(){
  function getUnenclosedText(selector,pointer,tag) {
    var str = $(selector).html();
    //determine start-pos and end-pos
    var startPos = str.indexOf(pointer+"</"+tag+">") + (pointer+"</"+tag+">").length;
    var endPos = str.indexOf("<"+tag,startPos);
    //if there are line-breaks, reset end-pos
    if (str.indexOf("<br",startPos)<endPos || endPos==-1) {
      endPos = str.indexOf("<br",startPos);
    }
    //return substring
    if (endPos==-1) {return str.substring(startPos).trim();} //if it was the last text in the container
    else {return str.substring(startPos,endPos).trim();}
  }
  
  console.log(getUnenclosedText("p","item 1","label")); //(selector,pointer,pointerTag)
  alert('Item 1: '+getUnenclosedText("p","item 1","label") +'\n'+ 'Item 3: '+getUnenclosedText("p","item 3","label"));
});
p {
  font-family:arial;
}

label {
  display:inline-block;    
  width:25%;
  font-weight:bold;
}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<p>
  <label>item 1</label> Capture me!
  <br /><br />
  <label>item 2</label> Don't capture me
  <label>item 3</label> capture me as well
  <br /><br />
  <label>item 4</label> Don't capture me either
</p>
(fiddle: http://jsfiddle/3uw8ux9t/9/)

I tried to make it as scalable as possible, using variables for all the parameters, so that the script is not limited to <p> and <label> anymore.

  • You now have to call the function getUnenclosedText(selector,pointer,tag), every time you want to extract a piece of text. The three parameters make the function scalable, so you can use it on various elements, not just <label> in <p>:
    • "selector" specifies which container element(s) you want to perform the function on. So if you have multiple <p>tags with different ID's for example, you can access a specific <p> tag, using its jQuery selector (e.g. "p#someid").
    • "pointer" specifies after which piece of text (e.g. "item 1", "item 2") you want to extract the unenclosed text.
    • "tag" specifies the tag-type that encloses the pointer (e.g. "label", "span").

If you have any questions, just ask them in the ments and I'll answer them or update this answer if need be, but I think you can find most of what you need on the internet.
Read this about how to use indexOf(), and you'll understand the most difficult parts of the code.

If the problem is to find text/HTML between labels, you could split the raw HTML text by the label tags into Array.

var items = paragraphNode.innerHTML.split(/<label>[\s\S]*?<\/label>/g);

The nice thing with this solution is that the regular expression can easily be changed to support other tags or more plex structures.

Demo is here: http://jsfiddle/x2u8ysx2/

$('p label:contains("item 1")').prop('nextSibling') will select that text node after the label.

If you want to style that using css then you'll have to use jQuery to wrap that text in a span and set the css color to red. Either that or color the content on the <p> tag red and set the color of that label back to it's original color.

Also keep in mind that what you get back from .nextSibling will be a text node and not a jQuery object.

You can't get that specific text using only jQuery, because it only deals with elements. The text that you want is between elements, and the parent element contains more text than you want.

You can get the DOM nodes from that label and until the next label, and get the text content from them.

In your example there are two text nodes and two br elements between the labels, so you would need to decide what you want from the br elements. In the example I have translated them to line breaks in the text:

var e = $('p label:eq(0)')[0].nextSibling;
var s = '';
while (e.tagName != 'LABEL') {
    if (e.tagName == 'BR') {
        s += '\n';
    } else {
        s += e.nodeValue;
    }
    e = e.nextSibling;
}
console.log(s);

Demo: http://jsfiddle/Guffa/1c2LpzrL/3/

jsfiddle DEMO

function captureStr(p, itm) {
    if(p.find('label').length > 0 && p.find('label:eq(0)').text().indexOf(itm) >= 0)
        return p.html().split("<br>")[0].split("</label>")[1].trim();
}

To test:

console.log(captureStr($('p'), "item 1"));

Capture me!

If you have many of these structure then you can loop through and call the function for each one.

Assuming the structure doesn't change much from what you posed the following will write the nodes out to the console based on the next sibling not being empty. I think this should work as many labels as you have in any number of paragraph tags. Here is a working JSFiddle (http://jsfiddle/RVAProgrammer/jsqxfgxe/)

console.log($('p').contents().filter(function () {
    var isTextNode = this.nodeType === Node.TEXT_NODE

    if (isTextNode) {
       if ($(this)[0].nextElementSibling === null) {
          return false;
       }
      return true;
    }

    return false;
}).text());

本文标签: javascriptHow to capture a string between two tagsStack Overflow