Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Highlighting when HTML and Xpath is given

Given the HTML as a string, the Xpath and offsets. I need to highlight the word.

In the below case I need to highlight Child 1

HTML text:

<html>
 <body>
       <h2>Children</h2>Joe has three kids:<br/>
       <ul>
        <li>
        <a href="#">Child 1 name</a>
        </li>
        <li>kid2</li>
        <li>kid3</li>
       </ul>
 </body>
</html>

XPATH as : /html/body/ul/li[1]/a[1]

Offsets: 0,7

Render - I am using react in my app. The below is what I have done so far.

public render(){
  let htmlText = //The string above
  let doc = new DOMParser().parseFromString(htmlRender,'text/html');
  let ele = doc.evaluate("/html/body/ul/li[1]/a[1]", doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); //This gives the node itself
  let spanNode = document.createElement("span");
  spanNode.className = "highlight";

  spanNode.appendChild(ele);
  // Wrapping the above node in a span class will add the highlights to that div
  //At this point I don't know how to append this span to the HTML String
  return(
    <h5> Display html data </h5>
    <div dangerouslySetInnerHTML={{__html: htmlText}} />
   )

I want to avoid using jquery. Want to do in Javascript(React too) if possible!

Edit:

So if you notice the Render function it is using dangerouslySetHTML. My problem is I am not able manipulate that string which is rendered.

like image 738
suprita shankar Avatar asked Mar 18 '17 03:03

suprita shankar


2 Answers

This is what I ended up doing.

public render(){
  let htmlText = //The string above
  let doc = new DOMParser().parseFromString(htmlRender,'text/html');
  let xpathNode = doc.evaluate("/html/body/ul/li[1]/a[1]", doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); 
  const highlightedNode = xpathNode.singleNodeValue.innerText;
  const textValuePrev = highlightedNode.slice(0, char_start);
  const textValueAfter = highlightedNode.slice(char_end, highlightedNode.length);
  xpathNode.singleNodeValue.innerHTML = `${textValuePrev}
                                         <span class='pt-tag'>
                                         ${highlightedNode.slice(char_start, char_end)}
                                         </span> ${textValueAfter}`;
  return(
    <h5> Display html data </h5>
    <div dangerouslySetInnerHTML={{__html: doc.body.outerHTML}} />
   )
like image 176
suprita shankar Avatar answered Sep 18 '22 12:09

suprita shankar


Xpath is inherently cross component, and React components shouldn't know much about each other. Xpath also basically requires all of the DOM to be created in order to query it. I would render your component first, then simply mutate the rendered output in the DOM using the Xpath selector.

https://jsfiddle.net/69z2wepo/73860/

var HighlightXpath = React.createClass({
  componentDidMount() {
     let el = document.evaluate(this.props.xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
     el.singleNodeValue.style.background = 'pink';
  },
  render: function() {
    return this.props.children;
  }
});

Usage:

<HighlightXpath xpath="html//body//div/p/span">
    ... app ...
</HighlightXpath>
like image 42
Andy Ray Avatar answered Sep 19 '22 12:09

Andy Ray