Retrieve all nodes where attributes contain a given string - c#

I want to retrieve all the RULE nodes that have one or more attributes that contains a given string. Once i found them I need to replace the string with a new one.
I tested those XPath query but they do not work:
string xpathquery = "/FIREWALL/ETH/RULE[contains(#*,'" + toTest + "')]"; //DOES NOT WORK
string xpathquery = "/FIREWALL/ETH/RULE[contains(attribute::*,'" + toTest +"')]"; //DOES NOT WORK
The strange thing is that if I use #attributename or attribute::attributename it actually works. Where is the error?
I am using the contains function because there could be two different cases, let's say I want to replace $HOST1 with $HOST2:
<RULE .... host="$HOST1"/> //NO PROBLEM
<RULE .... host="$HOST1:21"/> //I NEED TO REPLACE ONLY $HOST1, NOT THE ENTIRE STRING
I can't just set the Value attribute of XmlNode but I need to modify the string. Actually I don't know if XPath can handle this with a find and replace or something like this.

The query you're using checks the concatenated text of all the attributes. The correct syntax is:
string xpathquery = "/FIREWALL/ETH/RULE/#*[contains(.,'" + toTest + "')]/..";
In other words, find a matching attribute and return its parent element. Of course, if what you want to do is to work with the attribute values, you can dispense with the /.. on the end, in which case you'll be returned the actual attribute nodes and can just iterate through them modifying the values accordingly.

The standard XPath function contains() requires a single string as its first argument. When the first argument is a list of nodes (as in your case), only the string value of the first node in the provided node-set is used. This is how you get your current results.
Solution:
/FIREWALL/ETH/RULE/#*[contains(.,' + toTest + ')]

Related

Linq - Is Exact String in String Array

I'm trying to write a Linq query that loops through a set of Umbraco nodes and checks if it's Document Type Alias is in a string array. I've got something very close:
if (allowedDocTypes != null && allowedDocTypes.Length > 0)
{
allowedDocTypes = allowedDocTypes.Where(x => !string.IsNullOrEmpty(x)).ToArray();
nodes = nodes.Where(x => x.DocumentTypeAlias.ContainsAny(allowedDocTypes));
}
allowedDocTypes is a string array that includes the document types. The first line inside the if statement removes any empty strings from the array. Finally, I'm making use of the ContainsAny method to check if the document type alias is in the string array.
This almost works in that it'll check if the document type alias contains any of the string in the string array. However, it works for partial matches as well but I really need exact matches.
For example, the string array has a value of review in it. What ContainsAny appears to do is pull through all the nodes with a document type alias of review but it'll also pull through any with a document type alias of preview.
Is there a way to easily change this so that review would be an exact match rather than partial?
Thanks,
Ben
All you really should have to do is reverse the logic a bit and use Contains:
nodes = nodes.Where(x => allowedDocTypes.Contains(x.DocumentTypeAlias));

How to get a part of a string (url)?

I have the following url
http://example.com/pa/TaskDetails.aspx?Proj=A5AF5C0D-648A-4892-A995-CDA8013F2643&Assn=2A992D9C-C511-E611-80E4-005056A13B51
I need to extract the A5AF5C0D-648A-4892-A995-CDA8013F2643 portion of the url parameter:
Proj=A5AF5C0D-648A-4892-A995-CDA8013F2643
This can be in the middle or at the end of the url. I cannot guarantee the position of it. But i always starts with Proj= and end with &. The string between this is what i want. How can i grab this within C#?
It seems that you are trying to retrieve the IDFA from a url address. I think you can easily do that by applying regular expressions to the url string.
For example, the following:
[0-9a-fA-F]{8}[-][0-9a-fA-F]{4}[-][0-9a-fA-F]{4}[-][0-9a-fA-F]{4}[-][[0-9a-fA-F]{12}
Picks up every valid IDFA when applied to the URL string. You can add conditions for the head and tail of the IDFA to retrieve exactly what you are looking for:
Proj=[0-9a-fA-F]{8}[-][0-9a-fA-F]{4}[-][0-9a-fA-F]{4}[-][0-9a-fA-F]{4}[-][[0-9a-fA-F]{12}&
You can test the above Regex (regular expression) syntax on one of the many free online Regex applets (e.g. https://regex101.com/)
To apply Regex to your code, please see the following thread:
c# regex matches example
You may need to create a Uri and pass the value of its Query property to the HttpUtility.ParseQueryString method:
string value = HttpUtility.ParseQueryString(new Uri("http://example.com/pa/TaskDetails.aspx?Proj=A5AF5C0D-648A-4892-A995-CDA8013F2643&Assn=2A992D9C-C511-E611-80E4-005056A13B51").Query)["Proj"];
The method is defined in System.Web.dll by the way so you need to add a reference to this one.
string som = "http://example.com/pa/TaskDetails.aspx?Proj=A5AF5C0D-648A-4892-A995-CDA8013F2643&Assn=2A992D9C-C511-E611-80E4-005056A13B51";
int startPos = som.LastIndexOf("Proj=") + "Proj=".Length + 1;
int length = som.IndexOf("&") - startPos;
string sub = som.Substring(startPos, length); //<- This will return your key
This should do it.
One solution:
string param = HttpUtility
.ParseQueryString("http://example.com/pa/TaskDetails.aspx?Proj=A5AF5C0D-648A-4892-A995-CDA8013F2643&Assn=2A992D9C-C511-E611-80E4-005056A13B51")
.Get("Proj");

Using xpath in C#, I need to check both for the existence and value of an element

The xml doc contains "section" elements which, in turn contain "tag" elements. The xpath needs to check whether or not a section contains a tag named 'SALE_FIN_CONCSSN'. If it does, the tag must not have the value 'Listing'. If every section contained a SALE_FIN_CONCSSN tag, it would be easy to check the value, but that is not the case. A section may contain a SALE_FIN_CONCSSN tag with a different value or no SALE_FIN_CONCSSN tag at all. Here is one thing I tried, but it doesn't filter out the sections with SALE_FIN_CONCSSN tag = 'Listing'.
xpath = "Report/data/section[" +
"#type='salescomp'" +
" and (tag[#name!='SALE_FIN_CONCSSN'] or tag[#name='SALE_FIN_CONCSSN']/text()!='Listing')" +
" and tag[#name='GS_DATE_TIME_O_SALE.1']/text()!='Active'" +
"]/tag[#name='GS_GROSS_ADJ_PERCENT.1']";
XmlNodeList percents = xDoc.SelectNodes(xpath);
How about this:
//section[#type='salescomp' and ((tag[#name='SALE_FIN_CONCSSN' and text()!='Listing']) or tag[#name!='SALE_FIN_CONCSSN'])]
I haven't tested it yet. Could you put the link of the page?

C# cannot save apostrophe to XML

I tried to save apostrophe ' to XML, but always I get an error.
When I want to save new item, first I tried to find it. I use this
XmlNode letters = root.SelectSingleNode("//letters");
XmlNode oldFileLetter = letters.SelectSingleNode("letter[#name='"+letterName+"']");
but when letterName contains apostrophe ' I get an error, that path isn't closed
I also found this c# parsing xml with and apostrophe throws exception but when I did what Steven said, it's OK for apostrophe, but double quotes throw exception.
I need to pass " and ' too.
You also could replace the apostriphe by &apos;
letterName = letterName.Replace("'", "&apos;");
XmlNode letters = root.SelectSingleNode("//letters");
XmlNode oldFileLetter = letters.SelectSingleNode("letter[#name='"+letterName+"']");
Take a look at this thread about special chars on a xml file.
The issue here is that your XPath already has an apostrophe indicating the beginning of a string within the XPath, so any apostrophe in your letterName value would be interpereted as closing the string value.
Contrary to Felipe's advice, XPaths are not themselves XML, so replacing the apostrophes with &apos; will not work. It will avoid the error, but you won't find the node you're looking for if letterName contains an apostrophe. Also, there is no difference in C# between "'" and "\'", so that will not help either.
I'd suggest looping through the letter elements and identifying the one where #name has the value you're looking for:
XmlNode oldFileLetter = null;
foreach(XmlNode letterNameNode in letters.SelectNodes("letter/#name"))
{
if(letterNameNode.Value.Equals(letterName))
{
oldFileLetter = letterNameNode.ParentNode;
break;
}
}
The only other approach I know of involves rigging up a system to allow defining and using XPath variables in your paths, but that's usually overkill.
Have you tried escaping it as such:
\'
You have to write it as an entity i think...
I'm,not sure but i can recall having come across this issue once before.
Look at this wikipedia thread...
http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references
const string apo = "\'";
XmlNode letters = root.SelectSingleNode("//letters");
XmlNode oldFileLetter = letters.SelectSingleNode("letter[#name="+apo+letterName+apo+"]")

Finding an element by partial id with Selenium in C#

I am trying to locate an element with a dynamically generated id. The last part of the string is constant ("ReportViewer_fixedTable"), so I can use that to locate the element. I have tried to use regex in XPath:
targetElement = driver.FindElement(
By.XPath("//table[regx:match(#id, "ReportViewer_fixedTable")]"));
And locating by CssSelector:
targetElement = driver.FindElement(
By.CssSelector("table[id$='ReportViewer_fixedTable']"));
Neither works. Any suggestions would be appreciated.
That is because the css selector needs to be modified you were almost there...
driver.FindElement(By.CssSelector("table[id*='ReportViewer_fixedTable']"))`
From https://saucelabs.com/blog/selenium-tips-css-selectors-in-selenium-demystified:
css=a[id^='id_prefix_']
A link with an id that starts with the text id_prefix_.
css=a[id$='_id_sufix']
A link with an id that ends with the text _id_sufix.
css=a[id*='id_pattern']
A link with an id that contains the text id_pattern.
You were using a suffix which I'm assuming was not the partial link text identifier you were supposed to be using (unless I saw your html, which means try showing your html next time). *= is reliable in any situation though.
try using
targetElement = driver.FindElement(By.XPath("//table[contains(#id, "ReportViewer_fixedTable")]"));
Note this will check for all the elements that have id which contains (and not only ends with 'ReportViewer_fixedTable'). I will try to find a regex option that would be more accurate answer to you question.
This solution will work irrespective of the XPath version. First, create a method somewhere in your COMMON helper class.
public static string GetXpathStringForIdEndsWith(string endStringOfControlId)
{
return "//*[substring(#id, string-length(#id)- string-length(\"" + endStringOfControlId + "\") + 1 )=\"" + endStringOfControlId + "\"]";
}
In my case, below is the control ID in different version of my product ::
v1.0 :: ContentPlaceHolderDefault_MasterPlaceholder_HomeLoggedOut_7_hylHomeLoginCreateUser
v2.0 :: ContentPlaceHolderDefault_MasterPlaceholder_HomeLoggedOut_8_hylHomeLoginCreateUser
Then, you can call the above method to find the control which has static end string.
By.XPath(Common.GetXpathStringForIdEndsWith("<End String of the Control Id>"))
For the control ID's which I mentioned for v1 & v2, I use like below :
By.XPath(Common.GetXpathStringForIdEndsWith("hylHomeLoginCreateUser"))
The overall logic is that, you can use the below XPath expression to find a control which ends with particular string:
//*[substring(#id, string-length(#id)- string-length("<EndString>") + 1 )="<EndString>"]

Categories