How to convert complex xpath to css - css

I have a complex html structure. New to CSS. Want to change my xpath to css as there could be some performance impact in IE
Xpath by firebug: .//*[#id='T_I:3']/span/a
I finetuned to : //div[#id='Overview']/descendant::*[#id='T_I:3']/span/a
Now I need corresponding CSS for the same. Is it possible or not?

First of all, I don't think your "finetuning" did the best possible job. An element id should be unique in the document and is therefore usually cached by modern browsers (which means that id lookup is instant). You can help the XPath engine by using the id() function.
Therefore, the XPath expression would be: id('T_I:3')/span/a (yes, that's a valid XPath 1.0 expression).
Anyway, to convert this to CSS, you'd use: #T_I:3 > span > a
Your "finetuned" expression converted would be: div#Overview #T_I:3 > span > a, but seriously, you only need one id selection.
The hashtag # is an id selector.
The space () is a descendant combinator.
The > sign is a child combinator.
EDIT based on a good comment by Fréderic Hamidi:
I don't think #T_I:3 is valid (the colon would be confused with the
start of a pseudo-class). You would have to find a way to escape it.
It turns out you also need to escape the underscore. For this, use the techniques mentioned in this SO question: Handling a colon in an element ID in a CSS selector.
The final CSS selector would be:
#T\5FI\3A3 > span > a

Related

Fix Position of ThreeJS Model While Scrolling [duplicate]

Can I have an element that has an id that starts with or is completely numbers?
E.g. something like this:
<div id="12"></div>
Can I have a div with id as number?
Yes you can, but selecting/styling it with a CSS selector will be a pain.
id values that consist solely of digits are perfectly valid in HTML; anything but a space is okay. And although earlier HTML specs were more restrictive (ref, ref), requiring a small set of chars and starting with a letter, browsers never cared, which is a big part of why the HTML5 specification opens things up.
If you're going to use those ids with CSS selectors (e.g, style them with CSS, or locate them with querySelector, querySelectorAll, or a library like jQuery that uses CSS selectors), be aware that it can be a pain and you're probably better off staring the id with a letter, because you can't use an id starting with a digit in a CSS id selector literally; you have to escape it. (For instance, #12 is an invalid CSS selector; you have to write it #\31\32.) For that reason, it's simpler to start it with a letter if you're going to use it with CSS selectors.
Those links above in a list for clarity:
HTML5 - The ID Attribute
HTML4 - The ID Attribute and ID and NAME tokens
CSS 2.1 rules for IDs
Below is an example using a div with the id "12" and doing things with it three ways:
With CSS
With JavaScript via document.getElementById
With JavaScript via document.querySelector (on browsers that support it)
It works on every browser I've ever thrown at it (see list below the code). Live Example:
"use strict";
document.getElementById("12").style.border = "2px solid black";
if (document.querySelector) {
document.querySelector("#\\31\\32").style.fontStyle = "italic";
display("The font style is set using JavaScript with <code>document.querySelector</code>:");
display("document.querySelector(\"#\\\\31\\\\32\").style.fontStyle = \"italic\";", "pre");
} else {
display("(This browser doesn't support <code>document.querySelector</code>, so we couldn't try that.)");
}
function display(msg, tag) {
var elm = document.createElement(tag || 'p');
elm.innerHTML = String(msg);
document.body.appendChild(elm);
}
#\31\32 {
background: #0bf;
}
pre {
border: 1px solid #aaa;
background: #eee;
}
<div id="12">This div is: <code><div id="12">...</div></code>
</div>
<p>In the above:</p>
<p>The background is set using CSS:</p>
<pre>#\31\32 {
background: #0bf;
}</pre>
<p>(31 is the character code for 1 in hex; 32 is the character code for 2 in hex. You introduce those hex character sequences with the backslash, see the CSS spec.)</p>
<p>The border is set from JavaScript using <code>document.getElementById</code>:</p>
<pre>document.getElementById("12").style.border = "2px solid black";</pre>
I've never seen the above fail in a browser. Here's a subset of the browsers I've seen it work in:
Chrome 26, 34, 39
IE6, IE8, IE9, IE10, IE11
Firefox 3.6, 20, 29
IE10 (Mobile)
Safari iOS 3.1.2, iOS 7
Android 2.3.6, 4.2
Opera 10.62, 12.15, 20
Konquerer 4.7.4
But again: If you're going to use CSS selectors with the element, it's probably best to start it with a letter; selectors like #\31\32 are pretty tricky to read.
From the HTML 5 specs...
The id attribute specifies its element's unique identifier (ID). [DOM]
The value must be unique amongst all the IDs in the element's home
subtree and must contain at least one character. The value must not
contain any space characters.
There are no other restrictions on what form an ID can take; in
particular, IDs can consist of just digits, start with a digit, start
with an underscore, consist of just punctuation, etc.
An element's unique identifier can be used for a variety of purposes,
most notably as a way to link to specific parts of a document using
fragment identifiers, as a way to target an element when scripting,
and as a way to style a specific element from CSS.
Identifiers are opaque strings. Particular meanings should not be
derived from the value of the id attribute.
So... yes :)
From the HTML 4.01 specs...
ID must begin with a
letter ([A-Za-z]) and may be followed
by any number of letters, digits
([0-9]), hyphens ("-"), underscores
("_"), colons (":"), and periods
(".").
So... no :(
You can also select that type of id(though it is definitely not the best practice to create such an id that starts with a number) by doing the following:
document.querySelector('div[id="12"]'); //or
document.querySelectorAll('div[id="12"]'); //if you have multiple elements with equal ID.
From a maintainability standpoint this is a bad idea. ID's should be at least somewhat descriptive of what they represent. Prefix it with something meaningful to be compliant with what others have already answered with. For example:
<div id ="phoneNumber_12" > </div>
As pointed out in other responses, the answer is technically:
ID and NAME tokens must begin with a letter ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), and periods (".").
However, as a practical matter, you will be somewhat more limited if you want your documents to work with a variety of browsers, CSS editors, and JavaScript frameworks.
As noted in other responses, jQuery has problems with ids that contain periods and colons.
A more subtle problem is that some browsers have been known to mistakenly treat id attribute values as case-sensitive. That means that if you type id="firstName" in your HTML (lower-case 'f') and .FirstName { color: red } in your CSS (upper-case 'F'), a buggy browsers will not set the element's color to red. Because both definitions use valid characters for the id, you will receive no error from a validation tool.
You can avoid these problems by strictly sticking to a naming convention. For example, if you limit yourself entirely to lower-case characters and always separate words with either hyphens or underscores (but not both, pick one and never use the other), then you have an easy-to-remember pattern. You will never wonder "was it firstName or FirstName?" because you will always know that you should type first_name.
Same Question is Already ask
What are valid values for the id attribute in HTML?
While TJ Crowder's answer is conceptually good, it doesn't work for descendant CSS selectors.
Escaping only the first character followed by space does work however (as at Chrome 49)
Assume the following HTML snippet:
<td id="123456">
<div class="blah">
<div class="yadah">play that funky music</div>
</div>
</td>
The following statement:
document.querySelector("#\\31 23456 .blah .yadah").style.fontStyle = "italic";
correctly displays play that funky music
No, In experience, it has to start with a letter. You can use numbers if you want after the first character being a letter.
No. It has to start with a letter. See http://www.electrictoolbox.com/valid-characters-html-id-attribute/. You can use numbers after the first character, however, e.g. a1 or theansweris42.

Why we need to escape CSS?

Given the following examples which I picked up from here:
CSS.escape(".foo#bar") // "\.foo\#bar"
CSS.escape("()[]{}") // "\(\)\[\]\{\}"
Since .foo#bar is a valid CSS selector expression. Why we need to append \ before some characters? Suppose I want to write my own program which does the same task of escaping all the values/expressions in a CSS file then, how should I proceed?
PS: I am always confused about the escaping, how should I think when it comes to escaping some input?
You escape strings only when those strings contain special symbols that you want to be treated literally. If you are expecting a valid CSS selector as user input, you shouldn't be escaping anything.
.foo#bar is a valid CSS selector, but it means something completely different from \.foo\#bar. The former matches an element with that respective class and ID, e.g. <div class=foo id=bar> in HTML. The latter matches an element with the element name ".foo#bar", which in a hypothetical markup language could be represented as <.foo#bar> (obviously this is not legal HTML or XML syntax, but you get the picture).

Is there a way to escape non-alphanumeric characters in Nokogiri css?

I have an anchor tag:
file.html#stuff-morestuff-CHP-1-SECT-2.1
Trying to pull the referenced content in Nokogiri:
documentFragment.at_css('#stuff-morestuff-CHP-1-SECT-2.1')
fails with the error:
unexpected '.1' after '[#<Nokogiri::CSS:
:Node:0x007fd1a7df9b40 #type=:CONDITIONAL_SELECTOR, #value=[#<Nokogiri::CSS::Node:0x007fd1a7df9b90 #type=:ELEMENT_NAME, #value=["*"]>, #<Nokogiri::CSS::Node:0x007fd1a7df9cd0 #
type=:ID, #value=["#unixnut4-CHP-1-SECT-2"
]>]>]' (Nokogiri::CSS::SyntaxError)
Just trying talk through this - I think Nokogiri is complaining about the .1 in the selectorId, because . is not valid in an html id.
I don't own the content, so I really don't want to go through and fix all the bad IDs if it is avoidable. Is there a way to escape non-alphanumeric selectors in a nokogiri .css() call?
Assuming your HTML looks something like this:
<div id='stuff-morestuff-CHP-1-SECT-2.1'>foo</div>
The string in question, stuff-morestuff-CHP-1-SECT-2.1, is a valid HTML ID, but it isn’t a valid CSS selector — the . character isn’t valid there.
You should be able to escape the . with a slash character, i.e. this is a valid CSS selector:
#stuff-morestuff-CHP-1-SECT-2\.1
Unfortunately this doesn’t seem to work in Nokogiri, there may be a bug in the CSS to XPath translation that it does. (It does work in the browser).
You can get around this by just checking the id attribute directly:
documentFragment.at_css('*[id="stuff-morestuff-CHP-1-SECT-2.1"]')
Even if slash escaping worked, you would probably have to check the id attribute like this if it value started with a digit, which is valid in HTML but cannot be (as far as I can tell) expressed as a CSS selector, even with escaping.
You could also use XPath, which has an id function that you can use here:
documentFragment.xpath("id('stuff-morestuff-CHP-1-SECT-2.1')")

Capybara/Poltergeist: CSS ID with a colon raises Capybara::Poltergeist::InvalidSelector

I have a CSS selector with a colon in the name, which apparently is a problem.
Example:
selector = 'input#billing:street1'
find(selector)
I get the following error message:
The browser raised a syntax error while trying to evaluate the selector "input#billing:region_id" (Capybara::Poltergeist::InvalidSelector)
Is there any way to use the selector the way it is? I know that I could do something like that:
selector = 'billing:street1'
find(:xpath, ".//input[#id='#{selector}']")
but I'd prefer not to do it for various reasons.
I use Cucumber, Capybara, Poltergeist/PhantomJS
This is more of an educated guess based on my experience with CSS and Javascript, but you could try something like this:
selector = 'input#billing\:street1'
find(selector)
Notice the backslash in front of the colon, this escapes the character in CSS. For Javascript however, it is slightly different. You will need two slashes to escape the character. Like so:
selector = 'input#billing\\:street1'
find(selector)
I'm not sure which one would do the trick (if either would) since I have zero experience with Cucumber, Capybara, and Poltergeist/PhantomJS, but based on your code it looks as if you would want to try the double slash \\ option first.

What is caret symbol ^ used for in css when selecting elements?

I encountered a css selector in a file like this:
#contactDetails ul li a, a[href^=tel] {....}
The circumflex character “^” as such has no defined meaning in CSS. The two-character operator “^=” can be used in attribute selectors. Generally, [attr^=val] refers to those elements that have the attribute attr with a value that starts with val.
Thus, a[href^=tel] refers to such a elements that have the attribute href with a value that starts with tel. It is probably meant to distinguish telephone number links from other links; it’s not quite adequate for that, since the selector also matches e.g. ... but it is probably meant to match only links with tel: as the protocol part. So a[href^="tel:"] would be safer.
a[href^="tel"]
(^) means it selects elements that have the specified attribute with a value beginning/starting exactly with a given string.
Here it selects all the 'anchor' elements the value of href attribute starting exactly with a string 'tel'
The carat "^" used like that will match a tags where the href starts with "tel" ( http://csscreator.com/content/attribute-selector-starts )
It means a tags whose href attribute begins with "tel"
Example:
This is a link
will match.

Resources