3

I need to manipulate a string-variable with JavaScript, which has some html-content. I want to search for some elements, change them and wrap these elements with another div-container.

How can I get this:

var myArr = ['Foo', 'Bar'];
var contenthtml = "<p>Foo</p>
  <p>Lorem ipsum dolor sit amet</p>
  <p>Lorem <b>ipsum</b> dolor sit amet</p>
  <p>Lorem ipsum dolor sit amet</p>
  <p>Bar</p>
  <p>Lorem ipsum dolor sit amet</p>";

to this:

contenthtml = "<div class='foo'><h1>Foo</h1>
  <p>Lorem ipsum dolor sit amet</p>
  <p>Lorem <b>ipsum</b> dolor sit amet</p>
  <p>Lorem ipsum dolor sit amet</p></div>
  <div class='bar'><h1>Bar</h1>
  <p>Lorem ipsum dolor sit amet</p></div>";
user3142695
  • 15,844
  • 47
  • 176
  • 332
  • Regular expressions are possibly what you are after (though they can cause as much trouble as they can help...) – DA. Feb 14 '14 at 20:52
  • jQuery has a number of useful functions for operating on blocks of DOM elements, wrapping them in other elements, etc. – Barmar Feb 14 '14 at 20:54
  • @Barmar But I do not know how to use JQuery, as the html-code is in a variable. It is not part of the DOM. So I have these to variables (string and array) and need to get the manipulated string. – user3142695 Feb 14 '14 at 21:02
  • jQuery can convert an HTML string into disconnected DOM elements, manipulate it, and then convert it back to a string. If you learn jQuery, this will be much easier than trying to do this with regexp. – Barmar Feb 14 '14 at 21:04
  • @Barmer I really like JQuery much, so I'm very interested in a JQuery-solution. Can you give me a short example how to convert the string in a "disconnected" DOM? – user3142695 Feb 14 '14 at 21:06
  • @Barmar I think that's dependent on the HTML being valid (but, then again, that's true of Regex as well...) – DA. Feb 14 '14 at 21:13
  • @DA, regular expressions is not what the OP is after. http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 – Brian S Feb 14 '14 at 22:14
  • @BrianS REGEX isn't a silver bullet. But some times a viable bullet. I think we're missing a key bit of info here: where is the HTML string coming from? How much control does the OP have over it? – DA. Feb 14 '14 at 22:18
  • @user3142695 Could you tell me if my answer does what you want? – Toothbrush Feb 17 '14 at 10:50

3 Answers3

1

You can use a regular expression (similar to my other answer at https://stackoverflow.com/a/21803683/3210837):

var keywordsRegEx = keywords.map(function(x){return x.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');}).join('|');
var result = str.replace(new RegExp('<p>(' + keywordsRegEx + ')</p>\r\n((?:[ \t]*<p>(?:(?!' + keywordsRegEx + ').)*</p>(?:\r\n)?)*)', 'mgi'), '<div><h1 class="$1">$1</h1>\r\n$2</div>\r\n');

See http://jsfiddle.net/ncu43/1/ for a full example.

What the regular expression does is it matches <p>, one of the keywords, </p>, and then a paragraph (not containing one of the keywords) zero or more times.

Toothbrush
  • 2,080
  • 24
  • 33
1

I used some DOM to solve this problem. For those who prefer a DOM solution, rather than RegExp:

Append elements in a variable instead of a temporary DOM

Community
  • 1
  • 1
user3142695
  • 15,844
  • 47
  • 176
  • 332
  • I'm not sure what you mean. You asked to change a string into another string, as far as I could see. – Toothbrush Feb 17 '14 at 13:28
  • Yes. But it is a html string. So isn't a dom-manipulation the better way? – user3142695 Feb 17 '14 at 13:48
  • I suppose so, but a regular expression is generally faster that DOM manipulation as the RegExp is compiled. Can you include the code you used to achieve it, please? – Toothbrush Feb 17 '14 at 13:49
0

This would be a little bit easier with straight-up DOM replacement/wrapping (in fact, I wrote such a solution but re-wrote it when I saw your comment saying you needed string input), but here's a solution using just a string as input:

var myArr = ['Foo', 'Bar'];
var contenthtml = '<p>Foo</p>\n'
    + '<p>Lorem ipsum dolor sit amet</p>\n'
    + '<p>Lorem <b>ipsum</b> dolor sit amet</p>\n'
    + '<p>Lorem ipsum dolor sit amet</p>\n'
    + '<p>Bar</p>\n'
    + '<p>Lorem ipsum dolor sit amet</p>';
var elements = $.parseHTML(contenthtml);
var tmp = '';
$.each(elements, function(index, element) {
    $.each(myArr, function(i, e) {
        if (element.innerHTML == e) {
            elements[index] = $('<h1>' + e + '</h1>').get(0);
            return;
        }
    });
    if (elements[index].outerHTML) {
        tmp += elements[index].outerHTML + '\n';
    }
});
contenthtml = '<div class="foo">' + tmp + '</div>';
console.log(contenthtml);

jsfiddle

Brian S
  • 4,878
  • 4
  • 27
  • 46
  • Thank you very much. But there is still a problem. As the elements from the array will be modified to a h1-element, all elements from one h1-element to the next element should be wraped in a div-container. So in that example there should be two div-container: the first one from the h1-foo to h1-bar and the second from h1-bar to the next h1-element (in this case to the end) – user3142695 Feb 15 '14 at 04:50