This is not a typical use-case. I am afraid, there is no optimal solution for
this. However, you don't have to traverse the whole DOM tree - you may just go
through the Map obtained from the evaluateDOM() method. This could be a
bit faster and at least you will skip the nodes that do not have any style
assigned.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Unfortuantely, the internal data structures of jStyleParser are not suitable
for this. For efficiency, it would be necessary to create some index on
property values, which is quite expensive. With traversing the map, I mean the
following (very roughly):
map=CSSFactory.assignDOM(DOM,Url,media,inherit);for(Map.Entry<...>mapEntry:map.entrySet()){Nodenode=mapEntry.getKey();NodeDatanodeStyle=mapEntry.getValue();//test the style now}
This way, you should test all the node styles more efficiently than with
traversing the tree.
Radek
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
public List<node> getElementsByPropertyName(String Property)</node>
{
return this.PropertyDriven.get(Property);
}
}
Applied to url http://www.libero.it, it traversed a
Dom with about 7400 element, generating a "property-driven" map in few
millisec on my notebook (Processor Intel i5-480M ).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi, if you managed to solve the problem by this (relatively short) code, is it
still necessary to add some support to the library? Actually, I am a bit
afraid about the possible performance impact because building two maps takes
more time than building one map. I mean your code is fine, although I would
consider using the approach that I proposed above in your generateMap()
method. The difference is that you don't have to traverse all the DOM nodes
but only the elements affected by some style definitions.
Radek
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
It's quite easy, given a certain node, to get all his properties.
But how i can get all the nodes with a certain property? ( for example, how i
can get all the nodes in the document with the property margin-top?)
A solution could be make a loop for all the nodes in the dom, testing if the
node has that property. But is not so efficient.
Is there' an easy and quick way to do that?
This is not a typical use-case. I am afraid, there is no optimal solution for
this. However, you don't have to traverse the whole DOM tree - you may just go
through the Map obtained from the evaluateDOM() method. This could be a
bit faster and at least you will skip the nodes that do not have any style
assigned.
It's a pity, a function similar to org.w3c.Document.getElementsByTagName()
could be very useful!
I didn't understand you small improvement.
At the moment I get my map with:
map = CSSFactory.assignDOM(DOM, Url, media, inherit);
and when i want to access to a property (for example font-size) of the element
"el" I use:
NodeData nodeStyle = map.get(el);
String PropertyValue = nodeStyle.getProperty("font-size").toString();
Looping all of this code on every element in the DOM is not so quick! :(
Unfortuantely, the internal data structures of jStyleParser are not suitable
for this. For efficiency, it would be necessary to create some index on
property values, which is quite expensive. With traversing the map, I mean the
following (very roughly):
This way, you should test all the node styles more efficiently than with
traversing the tree.
Radek
IMHO, I'd love to have also this second "property-driven" map inside
JStyleParser.
I think quite all the people who works with css works also with html.
With this second map html parsing and css parsing will be more similar.
Generating this second map during the css parsing should be a small overhead.
May I highlight it as "requested feature"? ;)
I wrote this simple class:
public class PropertyDrivenMap {
private StyleMap OriginalMap = null;
private Document Dom = null;
private Map<string, list\<node=""> > PropertyDriven = new HashMap<>();</string,>
public PropertyDrivenMap(StyleMap OriginalMap, Document Dom)
{
this.OriginalMap = OriginalMap;
this.Dom = Dom;
}
public void GenerateMap()
{
NodeList DomNodes = this.Dom.getElementsByTagName("*");
for (int i = 0; i < DomNodes.getLength(); i++)
{
if (DomNodes.item(i).getNodeType() == Node.ELEMENT_NODE)
{
Element el = (Element) DomNodes.item(i);
NodeData nodeStyle = OriginalMap.get(el);
Iterator<string> iterator = nodeStyle.getPropertyNames().iterator();</string>
while ( iterator.hasNext() )
{
String Property = iterator.next();
List<node> NodeList = PropertyDriven.get(Property);</node>
if (NodeList == null)
{
NodeList = new ArrayList<>();
NodeList.add(el);
PropertyDriven.put(Property, NodeList);
}
else
{
NodeList.add(el);
}
}
}
}
}
public List<node> getElementsByPropertyName(String Property)</node>
{
return this.PropertyDriven.get(Property);
}
}
Applied to url http://www.libero.it, it traversed a
Dom with about 7400 element, generating a "property-driven" map in few
millisec on my notebook (Processor Intel i5-480M ).
There's no way to have something like this code built-in inside the library?
Hi, if you managed to solve the problem by this (relatively short) code, is it
still necessary to add some support to the library? Actually, I am a bit
afraid about the possible performance impact because building two maps takes
more time than building one map. I mean your code is fine, although I would
consider using the approach that I proposed above in your generateMap()
method. The difference is that you don't have to traverse all the DOM nodes
but only the elements affected by some style definitions.
Radek