Get more values from XPATH in Javascript - javascript

I have this HTML template:
<div class="item">
<span class="light">Date</span>
<a class="link" href="">2018</a>
(4pop)
</div>
<div class="item">
<span class="light">From</span>
<span>
<a class="link" href="" title="Bob" itemprop="url"><span itemprop="name">Bob</span></a>,
</span>
<span>
<a class="link" href="" title="Peter" itemprop="url"><span itemprop="name">Peter</span></a>
</span>
</div>
<div class="item">
<span class="light">For</span>
<a class="link" href="">Bak</a>,
<a class="link" href="">Cam</a>,
<a class="link" href="">Oli</a>
</div>
<div class="item">
<span class="light">Nat</span>
<a class="link" href="">Cool</a>
</div>
</div>
And my Javascript code:
var doc = new DOMParser().parseFromString(HTMLContent,'text/html');
var infos = doc.evaluate('//div[#class="item"]/span[1]', doc, null, XPathResult.ANY_TYPE, null);
var nodes = [];
for(var node = infos.iterateNext(); node; node = infos.iterateNext()) {
nodes.push(node);
console.log(node.textContent);
// Until here, all things works well ! Except the code from here:
var nodde = node.nextElementSibling.attributes;
nodde.forEach(function(item){
console.log(item);
});
}
My goal is to get the respective value for each categorie, for example:
Date = 2018, (4pop)
From = Bob, Peter
For = Bak, Cam, Oli
Nat = Cool
I tried to iterate: node.nextElementSibling.attributes but without any success !
Is there a way to get the expected result please ?

The HTML Document Object Model, DOM, is preferred as it's easier. XPATH is geared toward more rigid XML documents.
Using JavaScript, you would get data with something like:
var users = document.querySelectorAll('[itemprop=name]').textContent;
console.log(users);

Related

How do I select text inside a <span> that is inside an HTMLCollection of links <a> using JavaScript?

I'm trying to scrape some data for a fun personal project, and I'm new to JS. I'm trying to get an array of team names from an HTMLCollection (using Chrome Dev Tools). If there's an easier way I'm open to it. So far:
let vMidCollection = document.getElementsByClassName("v-mid");
vMidCollection[0]
QUESTION: Each <a></a> contains a <span></span> but I need an array of team names (underlined). Thanks in advance.
You can try this using querySelectorAll
const teamNames = [...document.querySelectorAll('.v-mid span.teamName')].map(e => e.textContent)
console.log(teamNames)
<a class="v-mid">
<div>
<span class="teamName">Test </span>
</div>
</a>
<a class="v-mid">
<div>
<span class="teamName">Test 1</span>
</div>
</a>
<a class="v-mid">
<div>
<span class="teamName">Test 2</span>
</div>
</a>
You can use the following
let vMidCollection = document.getElementsByClassName("v-mid");
team_names = []
Array.from(vMidCollection).forEach( (elem) => {team_names.push(elem.querySelector(".teamName").innerText)})
console.log(team_names)
<a class="v-mid">
<div>
Stuff
</div>
<span class="teamName">Tam 1 </span>
</a>
<a class="v-mid">
<div>
Stuff
</div>
<span class="teamName">Team 2</span>
</a>
<a class="v-mid">
<div>
Stuff
</div>
<span class="teamName">Team3</span>
</a>
It finds every element inside vMidCollection that has class="teamname" and appends it text to team_names

loop through divs for nested divs with href inside

<div class="view-content">
<div class="views-row views-row-1">
<div class="views-field">
<span class="field-content">
<a href="link1">Name for link1
<img src="image1">
</a>
</span>
</div>
<div class="views-field-title">
<span class="field-content">
<a href="link1">
</a>
</span>
</div>
</div>
<div class="views-row views-row-2">
<div class="views-field">
<span class="field-content">
<a href="link2">Name for Link2
<img src="image2">
</a>
</span>
</div>
<div class="views-field-title">
<span class="field-content">
<a href="link2">
</a>
</span>
</div>
</div>
I am using node with request, and cheerio to request the data and scrape accordingly.
I am seeking the href from link1 and link2, I got it to work for one link, but it does not scale out when I try to loop it.
const data ={
link:"div.views-field > span > a"
},
pageData = {};
Object.keys(data).forEach(k => {
pageData[k] = $(data[k]).attr("href");});
console.log(pageData);
Your approach with $(data[k]).attr("href"); is the right idea, but there's no loop here. There should be 2 elements matching this selector but your code only grabs the first.
Changing this to a [...$(data[k])].map(e => $(e).attr("href")) lets you get href attributes from all matching elements.
I'm not crazy about pageData being global and using a forEach when a map seems more appropriate, so here's my suggestion:
const $ = cheerio.load(html);
const data = {
link: "div.views-field > span > a",
};
const pageData = Object.fromEntries(
Object.entries(data).map(([k, v]) =>
[k, [...$(v)].map(e => $(e).attr("href"))]
)
);
console.log(pageData);

Advanced filling of prev and next buttons with jQuery

In a hidden list I have a variable list with this data (in this example www.domain.com/2009 is the current URL):
<ul id="WalkingYears" style="visibility: hidden; display:none;">
<li id="Walk2011"><img src="some-imga.jpg"></li>
<li id="Walk2010"><img src="some-imgs.jpg"></li>
<li id="Walk2008"><img src="some-imgf.jpg"></li>
<li id="Walk2007"><img src="some-imgg.jpg"></li>
<li id="Walk2006"><img src="some-imgh.jpg"></li>
<li id="Walk2005"><img src="some-imgj.jpg"></li>
<li id="Walk2004"><img src="some-imgk.jpg"></li>
<li id="Walk2003"><img src="some-imgl.jpg"></li>
<li id="Walk2002"><img src="some-imgz.jpg"></li>
<li id="Walk2001"><img src="some-imgx.jpg"></li>
</ul>
The above list is auto-generated and I can change this if I like; for example into:
<div id="Walk2011" data-target="http://domain.com/2011" data-img="some-imga.jpg" data-title="2011"></div>
<div id="Walk2010" data-target="http://domain.com/2010" data-img="some-imgs.jpg" data-title="2010"></div>
<div id="Walk2008" data-target="http://domain.com/2008" data-img="some-imgd.jpg" data-title="2008"></div>
<div id="Walk2007" data-target="http://domain.com/2007" data-img="some-imgf.jpg" data-title="2007"></div>
<div id="Walk2006" data-target="http://domain.com/2006" data-img="some-imgg.jpg" data-title="2006"></div>
<div id="Walk2005" data-target="http://domain.com/2005" data-img="some-imgh.jpg" data-title="2005"></div>
<div id="Walk2004" data-target="http://domain.com/2004" data-img="some-imgj.jpg" data-title="2004"></div>
<div id="Walk2003" data-target="http://domain.com/2003" data-img="some-imgk.jpg" data-title="2003"></div>
<div id="Walk2002" data-target="http://domain.com/2002" data-img="some-imgl.jpg" data-title="2002"></div>
<div id="Walk2001" data-target="http://domain.com/2001" data-img="some-imgz.jpg" data-title="2001"></div>
You see that the current URL (www.domain.com/2009) is not showing in this list.
Now I'd like to fill the prev and next navigation, based on the current url, using the values mentioned above (title, href, image src):
<a href="http://domain.com/2008" title="2008" id="balk-prev-btn" class="prev-btn left">
<img src="some-imgd.jpg" alt="2008">
<span class="icon"></span>
</a>
<a href="http://domain.com/2010" title="2010" id="balk-next-btn" class="next-btn right">
<img src="some-imgs.jpg" alt="2010">
<span class="icon"></span>
</a>
I guess I need to
first find out what the current URL is
then compare it to the data in the list
somehow point out the prev and next page
Also when having selected a certain variable (the name of a walker) the links in the list will be different and the URL will be www.domain.com/walkername/2009:
<div id="Walk2011" data-target="http://domain.com/walkername/2011" data-img="some-imga.jpg" data-title="2011"></div>
<div id="Walk2010" data-target="http://domain.com/walkername/2010" data-img="some-imgs.jpg" data-title="2010"></div>
<div id="Walk2008" data-target="http://domain.com/didnotwalk/2008" data-img="some-imgd.jpg" data-title="2008"></div>
<div id="Walk2007" data-target="http://domain.com/didnotwalk/2007" data-img="some-imgf.jpg" data-title="2007"></div>
<div id="Walk2006" data-target="http://domain.com/walkername/2006" data-img="some-imgg.jpg" data-title="2006"></div>
<div id="Walk2005" data-target="http://domain.com/didnotwalk/2005" data-img="some-imgh.jpg" data-title="2005"></div>
<div id="Walk2004" data-target="http://domain.com/didnotwalk/2004" data-img="some-imgj.jpg" data-title="2004"></div>
<div id="Walk2003" data-target="http://domain.com/walkername/2003" data-img="some-imgk.jpg" data-title="2003"></div>
<div id="Walk2002" data-target="http://domain.com/didnotwalk/2002" data-img="some-imgl.jpg" data-title="2002"></div>
<div id="Walk2001" data-target="http://domain.com/didnotwalk/2001" data-img="some-imgz.jpg" data-title="2001"></div>
In this case the prev and next button should only show the links with the walker name in it :) and should look like this:
<a href="http://domain.com/walkername/2006" title="2006" id="balk-prev-btn" class="prev-btn left">
<img src="some-imgg.jpg" alt="2006">
<span class="icon"></span>
</a>
<a href="http://domain.com/walkername/2010" title="2010" id="balk-next-btn" class="next-btn right">
<img src="some-imgs.jpg" alt="2010">
<span class="icon"></span>
</a>
Can someone help me?
tnx!
Okay so if you have this layout, this script should do the job
<div id="Walk2011" data-target="http://domain.com/walkername/2011" data-img="some-imga.jpg" data-title="2011"></div>
<div id="Walk2010" data-target="http://domain.com/walkername/2010" data-img="some-imgs.jpg" data-title="2010"></div>
<div id="Walk2008" data-target="http://domain.com/didnotwalk/2008" data-img="some-imgd.jpg" data-title="2008"></div>
<div id="Walk2007" data-target="http://domain.com/didnotwalk/2007" data-img="some-imgf.jpg" data-title="2007"></div>
<div id="Walk2006" data-target="http://domain.com/walkername/2006" data-img="some-imgg.jpg" data-title="2006"></div>
<div id="Walk2005" data-target="http://domain.com/didnotwalk/2005" data-img="some-imgh.jpg" data-title="2005"></div>
<div id="Walk2004" data-target="http://domain.com/didnotwalk/2004" data-img="some-imgj.jpg" data-title="2004"></div>
<div id="Walk2003" data-target="http://domain.com/walkername/2003" data-img="some-imgk.jpg" data-title="2003"></div>
<div id="Walk2002" data-target="http://domain.com/didnotwalk/2002" data-img="some-imgl.jpg" data-title="2002"></div>
<div id="Walk2001" data-target="http://domain.com/didnotwalk/2001" data-img="some-imgz.jpg" data-title="2001"></div>
jQuery based script:
var xlocation = "http://www.domain.com/walkername/2009".match(/(\/[a-zA-Z]+\/)(\d+)/); //sorry for ugly regexp --> ["/walkername/2009", "/walkername/", "2009"], also here should be used window.location.href , but for example lets use static string;
//find and filter only links which have 'walkername' in data-tagert
$el = $('#WalkingYears div[id^=Walk]').filter(function(i,el){
return $(el).attr('data-target').indexOf(xlocation[1]) > 0;
}),
//sort if divs is scrambeled
$elSorted = $el.sort(sorter);
prev = jQuery.grep($elSorted,function(el,i){
return $(el).attr('data-title').replace(/^\D+/g, '')*1<xlocation[2]*1
})
next = jQuery.grep($elSorted,function(el,i){
return $(el).attr('data-title').replace(/^\D+/g, '')*1>xlocation[2]*1
})
var sorter = function(a,b){
var a = $(a).attr('data-title').replace(/^\D+/g, '')*1,
b = $(b).attr('data-title').replace(/^\D+/g, '')*1
return b-a
}
//ADD href to buttons...
$('#balk-prev-btn').prop('href',$(prev).first().attr('data-target'))
$('#balk-next-btn').prop('href',$(next).last().attr('data-target'))
You`ll need to check if prevEl and NextEl still exists in case if current page is first or last. Also you will need to review regexp used for parsing url :)

Not able to change nested div in javascript dom

I am new to javascript and I am facing problems in dynamically changing the onclick attribute of the anchor tag in html. Below is my code:
function changeImage(){
var charAll = <?php echo json_encode($_SESSION['char_all']); ?>;
var charCount = 0;
for (var key in charAll) {
var charDiv = document.getElementById(key);
var anchorTag = charDiv.getElementsByTagName('a')[0];
anchorTag.onclick = function(){startChar('1', charAll[key].toString());};
}
}
<ul id="portfolio-list" data-animated="fadeIn">
<li id="character1">
<img src="character1.jpg" width="250px" height="280px" alt="" />
<div class="portfolio-item-content">
<span class="header">Play!</span>
<p class="body"></p>
</div>
<i class="more">></i>
<div class="post-info">
<div class="post-basic-info">
<h3 class="text-center">Character 1</h3>
</div>
</div>
</li>
<li id="character2">
<img src="character2.jpg" width="250px" height="280px" alt="" />
<div class="portfolio-item-content">
<span class="header">Play!</span>
<p class="body"></p>
</div>
<i class="more">></i>
<div class="post-info">
<div class="post-basic-info">
<h3 class="text-center">Character 2</h3>
</div>
</div>
</li>
</ul>
What I intend on doing is to change the onclick function of each of the <li> elements. The session variable $_SESSION['char_all'] is a dictionary in php, where the key is the character name (string) and the value is the character id corresponding to the character name in my database table. So, ideally the <a> tags under the <li> tags should get the onclick attribute of startChar('1', '1') (for character 1) and startChar('1', '2') (for character 2). But, what I end up with is startChar('1', '2') for both the characters.
Where am I going wrong? It might be something very silly that I am overlooking. But, I am not able to figure out. So, please help me out!
Your for in procedure referes to key which changes while iterating thorugh charAll.
As a solution (not tested), you might want to wrap the function in an outer anonymous-function and pass key to it:
(function(currentKey) {
anchorTag.onclick = function(){startChar('1', charAll[currentKey].toString());};
})(key);

jQuery or Javascript Click function change or add id

Is it possible to change the text "mars-on-newyork" from this links, this is how the links looks like:
<ul>
<li>
<a href="google.com/finder.php?offer=mars-on-newyork">
<img class="the-button-red"/>
</a>
</li>
<li>
<a href="google.com/finder.php?offer=mars-on-newyork">
<img class="the-button-green"/>
</a>
</li>
<li>
<a href="google.com/finder.php?offer=mars-on-newyork">
<img class="the-button-blue"/>
</a>
</li>
</ul>
This code changes my images only:
function changeIt(objName) {
var obj = document.getElementById(objName);
var objId = new Array();
objId[0] = "newyork";
objId[1] = "paris";
objId[2] = "tokyo";
var i;
var tempObj;
for (i = 0; i < objId.length; i++) {
if (objName == objId[i]) {
obj.style.display = "block";
} else {
tempObj = document.getElementById(objId[i]);
tempObj.style.display = "none";
}
}
return;
}
and here is the rest of the html from which the java script changes only the pictures:
<div id="newyork">
<a href="#">
<img src="newyork.jpg"/>
</a>
</div>
<div id="paris" style="display:none">
<img src="paris.jpg" border="0" alt="one"/>
</div>
<div id="tokyo" style="display:none">
<img src="tokyo.jpg" border="0" alt="two" />
</div>
<div style="display:none;">
<a id="one" href="#" onclick="changeIt('newyork');"><img src="newyork.jpg" border="0" alt="one"/></a>
</div>
<div>
<a id="one" href="#" onclick="changeIt('paris');"><img src="paris.jpg" border="0" alt="one"/></a>
</div>
<div>
<a id="two" href="#" onclick="changeIt('tokyo');"><img src="tokyo.jpg" border="0" alt="two"/></a>
</div>
If i click on
<a id="one" href="#" onclick="changeIt('paris');"><img src="paris.jpg" border="0" alt="one"/></a>
i want the text from the links on the ul to change from this:
href="google.com/finder.php?offer=mars-on-newyork
to this:
href="google.com/finder.php?offer=mars-on-paris
and if i click on
<a id="one" href="#" onclick="changeIt('tokyo');"><img src="paris.jpg" border="0" alt="one"/></a>
it changes it to
href="google.com/finder.php?offer=mars-on-tokyo
i want the java script to work like it does, how it changes the images but i also want to take advantage of the click to change the text.
thanks!
I see how it is now, i guess my post wasn't good enough to have piqued you're interest's, i guess i would have to pay a freelancer to help me, thanks anyways guys for your time and help!
Quick answer to "Is it possible to add or change and id from a link?":
$('#link').attr('id', 'yourNewId'); // Change id
Quick solution to "What I also want is not to just change the images but also the id or link"
$('#link').attr('href', 'yourNewUrl'); // Change link
I'm finding it a little hard to understand what you're trying to do, but...
what i also want is not to just change the images but also the id or link from the ul list e.g
OK, to change the link, i.e., the href property of all anchor elements in your ul list, assuming the URL has a fixed format and we can just replace whatever comes after the last "-":
// assume objName = "paris" or whatever
$("ul a").attr("href", function(i, oldVal) {
return oldVal.substr(0, oldVal.lastIndexOf("-") + 1) + objName;
});
If you pass the .attr() method a callback function it will call that function for each element and pass the function the current value - you then return the new value.
The elements in question don't seem to have an id at the moment, so I'm not sure what you mean by wanting to change it.

Categories

Resources