Consider the following snippet:
<Offering id=1 blah blah templateid=abc something=blah
gretre
rtert
ret
tr
/Offering>
<Offering id=2 blah blah templateid=def something=blah>
gretre
rtert
ret
tr
</Offering>
<Offering id=3 blah blah templateid=ghi something=blah>
gretre
rtert
ret
tr
</Offering>
Given that all I know is the template id, I need to return the whole Offering node that contains it. i.e. for templateid=def, I need to return:
<Offering id=2 blah blah templateid=def something=blah>
gretre
rtert
ret
tr
</Offering>
I've tried all sorts but the closest I can get is something along the lines of (?s)<Offering.+?templateid=def.+?</Offering> which returns from the first offering until the end of the offering containing my template id. I understand why but nothing I've tried can fix it. I'm guessing lookarounds but I just can't get it right.
How can I return the whole offering node?
You could modify your regex using negation and I would probably use a word boundary as well.
<Offering[^>]*\btemplateid=def[^>]*>[^<]*</Offering>
If you have other tags inside of this tag, you could do ...
(?s)<Offering[^>]*\btemplateid=def.+?</Offering>
This should work but please notice that I escaped the / character, and you may not need to do that depending on what language you're using:
(<Offering[^>]* templateid=ghi [^>]*>[^<]*<\/Offering>)
As you say you "need to return the whole Offering node", the arguably simpler, safer and more readable way would be a DOM parser. I've included examples of how you might do this in JavaScript and PHP below.
PHP
$doc = new DOMDocument();
#$doc->loadHTML($testStr); //Only needed if you're loading HTML like in the example which has repeated attributes and other things that could cause errors
$body = $doc->getElementsByTagName('body')->item(0);
$templateID = 'def';
$myNode = null;
foreach($body->childNodes as $node)
{
if($node->nodeName=='offering')
{
if($node->attributes->getNamedItem('templateid')->nodeValue == $templateID)
{
$myNode = $node;
}
}
}
//$id = $myNode->attributes->getNamedItem('id')->nodeValue;
//$html = $doc->saveHTML($myNode)
JavaScript
var testStr = document.getElementById('str_container').innerHTML;
var parser = new DOMParser();
var doc = parser.parseFromString(testStr,'text/html');
var templateID = 'def';
var myEl = null;
for(var i=0,c=doc.body.children.length;i<c;i++)
{
if(doc.body.children[i].getAttribute('templateid')===templateID)
{
myEl = doc.body.children[i];
}
}
//var id = myEl.id;
//var html = myEl.outerHTML;
console.log(myEl || 'not found');
JavaScript >= IE8
var testStr = document.getElementById('str_container').innerHTML;
var parser = new DOMParser();
var doc = parser.parseFromString(testStr,'text/html');
var templateID = 'def';
var myEl = doc.body.querySelector('offering[templateid='+templateID+']');
//var id = myEl.id;
//var html = myEl.outerHTML;
console.log(myEl || 'not found');
Related
var totalList_grps = element.all(by.css('p.group-name-text'));
totalList_grps.getText().then(function(text){
console.log('Total list of joined groups : ' + text);
});
Tried the above code for printing list of group names.
Got Output :Total list of joined groups : Party,Innovation,capsLock,Gym,Sunrisers
AW,Big Boss.
Now i need to search for a particular name using if else condition and i tried the second set of code, but its not displaying any output not even a error.
totalList_grps.getText().then(function(itemList) {
expect(itemList).toContain('Big Boss');
});
Here is developers code
1) use by.cssContainingText():
var bigBoss = element(by.cssContainingText('p.group-name-text', 'Big Boss'));
// then you can call click(), getText(), getAttribute('') on found element as following:
bigBoss.click();
2) use elements.filter():
var bigBoss = element.all(by.css('p.group-name-text'))
.filter(function(it){
return it.getText().then(function(txt){
console.log('txt: ' + txt);
return txt === 'Big Boss' || txt.includes('Big Boss');
});
})
.first();
3) use await with combination of if/else
var allNames = element.all(by.css('p.group-name-text'));
var length = await allNames.count();
var matchedIndex = -1;
for(var i=0;i<length;i++) {
var name = await allNames.get(i).getText();
if (name === 'Big Boss' || name.includes('Big Boss')) {
matchedIndex = i;
console.log('matchedIndex = ' + matchedIndex);
break;
}
}
var bigBoss = allNames.get(matchedIndex);
We can implement option 3 without using await, but the code will be not easy readable and more complex than current.
FYI, If you want to use await/async, you need to disable protractor promise management (know as control flow). You can't use both in your code at same time.
I have a script that takes the current document and looks for a user defined string using findText. If that string contains a quote (like: Bob's Burgers). findText does not find it. I know it uses regular expressions, but I cannot figure out how to format the expression so it finds this properly.
code example:
var target = "Bob's Burgers";
var body = DocumentApp.getActiveDocument().getBody();
try
{
var searchResult = body.findText(target);
//does not find the text. But can find Bob easily.
}
catch(e) { ...}
I tried the findText method using the code from this post:
function highlightText(findMe) {
var body = DocumentApp.getActiveDocument().getBody();
var foundElement = body.findText(findMe);
while (foundElement != null) {
// Get the text object from the element
var foundText = foundElement.getElement().asText();
// Where in the Element is the found text?
var start = foundElement.getStartOffset();
var end = foundElement.getEndOffsetInclusive();
// Change the background color to yellow
foundText.setBackgroundColor(start, end, "#FCFC00");
// Find the next match
foundElement = body.findText(findMe, foundElement);
}
}
function myFunction() {
highlightText("Bob’s Burger");
}
Result:
Hope this helps.
Use \` instead of ` to escape it.
var target = "Bob\'s Burgers";
I'm trying to create a function that I can use to outdent (versus indent) a specific amount.
Here is what I have so far. This removes all tabs at the beginning of the lines. I think I need to create a dynamic pattern or use a function but I'm stuck:
var outdentPattern:RegExp = /([\t ]*)(.+)$/gm;
function outdent(input:String, outdentAmount:String = "\t"):String {
var outdentedText:String = input.replace(outdentPattern, outdentAmount + "$2");
return outdentedText;
}
Here is test data:
<s:BorderContainer>
<html:htmlOverride><![CDATA[
<script>
var test:Boolean = true;
test = "string";
</script>]]>
</html:htmlOverride>
</s:BorderContainer>
The test would be remove one tab, remove two tabs, etc.
Expected results at one tab would be:
<s:BorderContainer>
<html:htmlOverride><![CDATA[
<script>
var test:Boolean = true;
test = "string";
</script>]]>
</html:htmlOverride>
</s:BorderContainer>
And two tabs:
<s:BorderContainer>
<html:htmlOverride><![CDATA[
<script>
var test:Boolean = true;
test = "string";
</script>]]>
</html:htmlOverride>
</s:BorderContainer>
And three tabs with the inner tabs (whitespace) collapsing down:
<s:BorderContainer x="110" height="160" width="240" y="52">
<html:htmlOverride><![CDATA[
<script>
var test:Boolean = true;
</script>
]]></html:htmlOverride>
</s:BorderContainer>
Interesting note:
The editor on SO is outdenting when you click code button when the code is already indented.
You could either construct a RegExp object from a template, or you could use the regular expression several times:
var temp:String = '^[\t ]{0,';
function outdent(input:String, amount:Number = 1):String {
return input.replace(new RegExp(temp + amount.toString() + '}', 'gm'), '');
}
Or:
var pattern:RegExp = /^[\t ]/gm;
function outdent(input:String, amount:Number = 1):String {
for (var i:Number = 0; i < amount; i++)
input = input.replace(pattern, '');
return input;
}
I'm looking for a way to search text on my MongoDB escaping some characters.
For example:
In the collection contacts there is a document with "john.doe" in field name
{
_id: ID
...
name : "john.doe",
...
}
("john.doe" could be "j.ohndoe" or "j.o.h.n.d.o.e" or "jo.hn.do.e", you name it)
I want to find it searching for "johndoe", not only "john.doe" (ignoring "."). It would be great to use directly findOne.
Is there a way to do this?
Thank you very much :)
I don't think it's possible using purely MongoDB queries. However, you can you MongoDB map reduce to get filtered documents or perform such actions on client side. I know it will not be an elegant solution but at least will work.
Please see https://docs.mongodb.org/manual/core/map-reduce/
Example
function findByKey(key)
{
var keys =
db.contacts.mapReduce(function(){
var re = /\./igm;
var txt = this.name.replace(re,"");
var re = new RegExp(u_name);
if(re.exec(txt)!= null)
{
emit(1, this._id);
}
}, function(k, v){
return {keys: v};
},
{
out:{inline:true},
scope: {u_name:key}
});
if(keys.results.length > 0)
{
var arKeys = keys.results[0].value.keys;
return db.contacts.find({_id:{$in: arKeys}});
}
else
{
return null;
}
};
var data = findByKey("john doe");
After running above script, variable data will hold all documents having "john doe" including j.ohn.doe or john.doe so ignoring all periods.
I have a simple but invisible (for me) error in code. Can you help me?
With this code in my php file:
$location = $xpath2->query("//script")->item(1)->textContent;
I got (select) this:
<script class="" type="text/javascript">
//<![CDATA[
var html = '';
var lat = 44.793530904744074;
var lang = 20.5364727973938;
if (GBrowserIsCompatible())
{
var map = new GMap2(document.getElementById("map_canvas"));
var ct = new GLatLng(lat, lang);
map.setCenter(ct, 15);
map.addControl( new GSmallMapControl() );
//map.addControl( new GHierarchicalMapTypeControl () );
var gm=new GMarker(ct);
if(html != '') {
GEvent.addListener(gm, "click", function() {
this.openInfoWindowHtml( html );
});
}
map.addOverlay(gm);
map.enableContinuousZoom();
map.enableInfoWindow();
}
//]]>
</script>
Then I try to fetch 'lat' and 'lang' with this code:
$location = $xpath2->query("//script")->item(1)->textContent;
preg_match('/var\s+lat\s+=\s+(\d+\.\d+)\s*;/', $location, $lat);
preg_match('/var\s+lang\s+=\s+(\d+\.\d+)\s*;/', $location, $lng);
$data['lat'] = $lat[1];
$data['lng'] = $lng[1];
But always show that lat and lang is 0, 0 when they should be 44.34534 and 20.5345.
PLEASE HELP! where you think that I'm wrong (my English is not very well, sorry for that)
Maybe something like below. Beware though you're trying to parse JavaScript.
preg_match('/(?:^|(?<=\s))var\s+lat \s* = \s* (?=[^;]*\d) ([+-]?\d*\.?\d*)\s*; /x', $location, $lat);
preg_match('/(?:^|(?<=\s))var\s+lang\s* = \s* (?=[^;]*\d) ([+-]?\d*\.?\d*)\s*; /x', $location, $lng);
Run sample: http://www.ideone.com/SEgVb
Or, just try to get more general information:
preg_match('/(?:^|(?<=\s))var\s+lat \s*=\s* ([^;]*) \s*; /x', ...
Try like this:
preg_match('/var\s+lat\s+=\s+([\d.-]+)/', $location, $lat);
preg_match('/var\s+lang\s+=\s+([\d.-]+)/', $location, $lng);
The [\d.-]+ matches any group with numbers . or - (lat/lon can be negative)