Icon fonts

April 24, 2013 1 comment

Icon fonts are a great way to enhance the performance of your website. I decided to put together a list of resources to help you understand, create and integrate icon font into your website.

Why use icon fonts?

First of all, what’s the big fuss about icon fonts? The basic idea is that instead of having tens of small images (and of course, tens of small HTTP requests) you embed all those images as characters into a font. Having only one request of a bigger size it is highly recommended instead of having multiple smaller requests, as the overhead of a HTTP request is huge in bandwidth and time.

You can also use sprites, but this approach has several benefits. First of all, it is easier and your code will be cleaner. When using sprites, the images will have only one resolution and one color. With icon fonts, you can set different colors and sizes for your icons without having to download another set – you actually set the font color and size. Here’s a demo.

There are some downsides, but I would say none of them major. Editing an icon font could be a little bit harder than editing just a simple image. Also multicolor icons are not suitable to be embedded in icon fonts. But the trend now is to have cleaner pages and icons, so multicolor icons could not be on your wishlist anyway.

As with any new feature, the biggest question is browser support. Good news here: all major browsers are on board.

If this convinced you, everything comes down to two things: creation and integration.

Creation of icon fonts

Editing

Basic idea is simple: vectorize your image into SVG images and embed them all into one SVG font. For this you can use InkScape and, as a beginner, a comprehensive tutorial and a video tutorial can be of great help.

Tip: It is recommended to fill in the name for each glyph (glyph-name XML attribute) in the SVG font. This way anyone with a text editor can easily identify the glyphs in the SVG font and change the unicode mapping for example.

Conversion

The end result will be an SVG font, but as you saw browsers support different formats. Now it comes to converting the SVG font into other formats.
For TTF I used to use FontSquirrel, but there are other better choices. http://fontface.codeandmore.com/ was a good and very fast online converter, but unfortunately you have to pay for it, though it’s only $8 per year.

What I currently use is http://onlinefontconverter.com/ to convert from SVG to TTF and WOFF. I don’t know why but usually EOT conversion got stuck so I use http://www.font2web.com/ for this final step. You can also use http://www.freefontconverter.com/ but it doesn’t convert to EOT, so again you will need font2web.

Integration of icon fonts

Font definition

To define a font you should use @font-face in your CSS and that’s pretty much it.
A basic common code sample will look like this:

@font-face {
    font-family: "MyFont";
    src: url('myfont.eot');
    src: url('myfont.eot?#iefix') format('embedded-opentype'), /* IE6 fix */
        url('myfont.woff') format('woff'),
        url('myfont.ttf') format('truetype'),
        url('myfont.svgz#MyFont') format('svg'),
        url('myfont.svg#MyFont') format('svg');
    font-weight: normal;
    font-style: normal;
}

@font-face {
    font-family: "MyFont";
    src: url('myfont_bi.eot');
    src: url('myfont_bi.eot?#iefix') format('embedded-opentype'), /* IE6 fix */
        url('myfont_bi.woff') format('woff'),
        url('myfont_bi.ttf') format('truetype'),
        url('myfont_bi.svgz#MyFontBoldItalic') format('svg'),
        url('myfont_bi.svg#MyFontBoldItalic') format('svg');
    font-weight: bold;
    font-style: italic;
}

Or if you’re using SCSS and Compass, which I highly recommend, then the above sample will become:

@import "compass/css3";
 
@include font-face('MyFont', font-files('myfont.eot', 'myfont.woff', 'myfont.ttf', 'myfont.svgz', 'myfont.svg'));
@include font-face('MyFont', font-files('myfont_bi.eot', 'myfont_bi.woff', 'myfont_bi.ttf', 'myfont_bi.svgz', 'myfont_bi.svg'), bold, italic);

Icon usage

Now that you declared your font you can use the icons. I will show below a few examples.

<span class='icon star' aria-hidden="true"></span>

<span data-icon='S' aria-hidden="true"></span>

… and the CSS …

.icon:after {
    font-family: "MyFont", sans-serif;	
    font-size: 12px;
    line-height: 12px;
    speak: none;
}
.icon.star:after {
    content: "S";
}
.icon.star-empty:after {
    content: "s";
}

[data-icon]:after {
    font-family: "MyFont", sans-serif;	
    font-size: 12px;
    line-height: 12px;
    content: attr(data-icon);
    speak: none;
}

For the first icon I split the declaration in two, so that you can easily add other icons as well. Of course, IE7 does not have support for :after, but, oh well, if you really need it, I think you can live without icons. Second form it’s more generic and it has the same browser support as the first one.

Notice the aria-hidden attribute and speak CSS property added here for accessibility purposes. The preferred way will be the speak property, but unfortunately there is almost no support for CSS2 Aural Style Sheets or CSS3 Speech.

In the end, a few free icon fonts:

Categories: Web

Internet and mobile conference in Bucharest – day 3

September 25, 2012 2 comments

I guess I was so bored about the last day speakers that I forgot to write the post about the final day.

Come on, it wasn’t that boring, at least not entirely. On the plus side I liked Ionut Oprea’s presentation about the Romanian blogging scene and different marketing campaigns made with bloggers. The blogging world in Romania is not that big or influential as other Western ones, but it’s steadily growing and there are major bloggers that are moving to the professional side. Encouraging.
Also encouraging is that online marketing agencies are started to push for YouTube advertising. I’m not thrilled that Google’s cash flow is growing, but this trend could also result in that the online TV could take over in matter of years the classical one.

As usual, Dan Virtopeanu was dealing with some cool aspects in the mcommerce space, as one of the speakers at the end of the day.

On the other end, it was the presentation “How to increase conversion rate, display relevant content to your visitors and get quality leads for websites and online shops” by Adrian Ursu and Ana Bucuroiu from Dynamicweb. It was even more boring than its long title – we practically found out their company offer in one long hour.

And now the overall conclusion. But first some administrative stuff. I was annoyed (not much) about the scanning of the badge, every time you enter or exit a conference room. I understand that the organizers wanted to check the attendance and even have some contacts for follow-up. But it was a conference about future of online and mobile. There were some speakers talking about NFC. Just put a few RFID gate readers and voila, problem solved. You have seamless attendance tracking, without any man power costs and you could even cover a wider area.

Altogether, IMWorld was an interesting conference, focused on the online marketing industry. Mobile was clearly one of the hottest topics and, at least, slightly touched by all (interesting!) speakers. A new emerging field, m-commerce, is on the rise and at this moment the numbers could not be totally relevant, but the trend should be.

day 1, day 2

Categories: Technology

Internet and mobile world conference in Bucharest – day 2

September 21, 2012 2 comments

I would say that the second day of the conference was a bit more interesting than the first one, at least for me as a developer.

I would recognize three more in-depth technical presentations. First one was given by Alvin Richards, Technical Director for 10 GEN, the company that created MongoDB. His presentation was about NoSQL databases, but with a very strong focus on MongoDB. David Mytton, founder of Server Density, backed up with his presentation and three study cases about NoSQL databases – MongoDB, Cassandra and CouchDB. From his presentation, I would give a try to MongoDB, taking into account performance and features.

Another technical presentation, this time from the client side area, was given by Andrei Ismail, Lead Front-End Developer at UberVu, about Mosaic a JavaScript framework for single page applications. He gave us insights about the development process, barriers encountered and important features of the framework. I would recommend you to check out at least the application demo developed with this framework.

Another presentation, not a technical one this time, but engaging and aggregating some interesting numbers was given by Doina Costache from Google. She gave some interesting figures for mobile adwords. If I remember correctly, only 8% of mobile queries are matched queries, but CTR on mobile adwords is 12%. So a growing opportunity for marketers.

On the other end, I was disappointed by the presentation from Nick Nicolescu, Territory Manager SEA at VMWare, which was nothing more than reading prices of the VMWare offer list from the slides.

I will come back about day 3, the final one, and general conclusions about the event.

day 1, day 3

Categories: Technology Tags:

Internet and mobile world conference in Bucharest – day 1

September 19, 2012 3 comments

Today was the first day of the Internet & Mobile World conference in Bucharest. I attended quite a few presentations, mostly presentations of case studies, with more focus on the bigger picture and less on the in-depth solution and implementation.

One concept present in two of them caught my attention – Remote Expert. The idea is simple: give access to experts to a wider range of people through some kind of teleconferencing means. Practically it is an older concept, but I like that it is becoming mainstream. Two speakers from Cisco presented its applications in banking and healthcare. A bank in Canada opened branches in remote areas and created in those branches hi-def teleconferencing rooms to offer its clients access to a wider area of financial experts. The second case study was in the healthcare industry with a focus on its applications on SMURD, the Romanian medical emergency service. Highly trained doctors from four main medical centers were connected with smaller divisions in remote areas and they were able to save lives through their expertise.

I was just leaving these presentations and I got the chance to test a similar application in the banking industry. Citibank, one of the leaders in the online banking market in Romania, launched OnlineBranch. It is an online service, so even accessible to a broader range of people, through which you can discuss with the bank financial advisers. Unfortunately the internet connection was poor and I couldn’t connect. It supposed to work from a mobile phone as well, but 3G connection wasn’t again enough. I personally think that this kind of low bandwidth cases should be targeted too, but I’m confident that they will remedy this in the future.

And if we’re talking about bandwidth, I gladly saw that satellite internet is becoming cheaper. At one of the booth, Tooway was advertising its home packages, starting with 20 EUR/month (for 2Mbps download and 1Mbps upload for first 2Gb). It is not yet affordable for the average consumer, but my hopes are high for the next few years.

day 2, day 3

Categories: Technology Tags:

Responsive design. One web. Semantic CSS.

September 18, 2012 Leave a comment

A new buzzword hit the streets of web development lately: responsive design. But what is it? If I wouldn’t trust Wikipedia(not saying that I don’t) and I would have to give my own definition, I would say that it is the ability of a web site to adapt to the user’s browsing device and offer the optimal experience, look and feel.
As usual, from theory to practice, there is a long and hard way. When talking about implementation, responsive design is an umbrella for a series of web development techniques and patterns. I will try to describe some of them in the next lines.
First of all responsive design starts with user device browser detection. I already wrote an article on the matter and I will come to this subjects on future posts as well. Now I will just enumerate the main techniques without focusing on a specific framework.

  • Device information repository. It is usually done on server side using the HTTP User-Agent header and mapping it against a database of devices. This database contains information about the device hardware and software like: name, manufacturer, input device (trackball, keyboard, touch screen), OS, browser, support for video, audio and image formats and many more. The most well known device repositories are OpenDDR (free), WURFL(free for non-commercial use) and DeviceAtlas (commercial). Apache DeviceMap is a new one, but it’s not on a stable release yet.
  • Pattern recognition. If you need just basic device detection, like to distinct only between mobile and desktop, you can use the browser name and map it against a list of given patterns (e.g. contains iPhone or Android). Needless to say that this method has a high failure rate and it doesn’t give you detailed information about the device and its capabilities. This technique can be applied on the server side using HTTP User-Agent header or on the client side using the window.navigator JavaScript object and its properties (e.g. appName)
  • Features recognition. This technique is applied on client side in JavaScript. This is only a part of a broader technique, progressive enhancements, which I will detailed it later on.

As soon as you’ve identified the user device, your website has several options on how to react. You can create different websites for mobile and desktop (and even one for tablets), you can create a desktop website and transcode it for mobiles/tablets or you can create only one, smart enough to adapt to all devices (existing and upcoming). And this is revealing the concept of One web. But what this concept implies, a concept for each W3C is lobbying as one of the most important guideline in web development? It is practically the same thing as responsive design, or I would say the best method to implement it, to have one website that can offer the best user experience no matter on the browser that it is accessing it.

Is it easy to implement? I would say so, but you need to have a few important things in mind. Let’s start with the most important one: content-layout separation. As we said you want to have only one website, which actually means one content. But the layout, how it is rendered and how it interacts with the user, is different for each device. If you’re familiar with the MVC concept, this is similar, but applied to your markup. The advantages are obvious: you will be able to maintain one content, your website can react differently if needed and you can clearly delimit the tasks between content editors and web developers.

As soon as we made the separation we can leave the content in the content editors’ hands and we can focus on the web development part. But do we really need to develop one layout for desktops and one for mobiles? And another one for tablets? Or even one for each type of mobile – featured, smartphone etc? Not quite. Again if you’re structuring and modularizing your website, you can get away much easier.

To easily plug in different layouts you definitely must use CSS. CSS Zen Garden is a clear example that proves its power, by rendering the same content in hundreds of different ways. But CSS alone is only a tool, you will need a technique that will enable you to unleash this power. And now we’re coming to the broader discussion of semantic CSS. Using it will gave you this level of pluggability and the good news is that to apply it you need just a mindset switch. Even though you’re developing a layout using CSS, think only at its semantics. This way it will become easy to link a content with the layout. Let’s say that you want to define the CSS class for the page title, which is displayed in blue, bold and with a double font. You will call that class title and not blue_bold_double_text. Sometime, this will not be as obvious as in this example, but always think first of the semantics and ask yourself the question: Why and when I would use this CSS class? Forget about specifics.
There are a few other related tips that you might find useful:

  • Give your CSS classes short, but meaningful names. Even though shorter is desirable, do not trade meaning over size. Do not abbreviate, further down the road you or some other developer may forget the meaning.
  • Use the semantic of HTML tags instead of defining new CSS classes, where appropriate. It is preferable to use H1 instead of .title and H2/3 instead of .sectionTitle.
  • Use the new HTML tags instead of the deprecated ones. STRONG is preferable to B, as it is related to semantic instead of layout.
  • Use as few CSS classes as possible. It will be harder to remember which class is for what if you have hundreds of them and when to use one over the other. Prefer using contextual references in CSS selectors or combining existing classes rather than creating new classes.

You structured your content and layout and now you have to develop it. There is an old concept, liquid layout, but I think it still can suit most needs. The idea is to develop a layout that can easily fit in different screen resolutions. This will translate mostly into using relative positioning and relative sizes instead of absolute ones.

We covered how a website should look like, but what about how it should feel, how it should interact with the user? I mentioned earlier about progressive enhancements and I already describe it in a previous post, so I will just restate it. The term sounds very complicated and futuristic, but it is not rocket science. It is not a framework or a new technology to learn and use. It is only a change of mindset. Mainly this applies to JavaScript and you have to keep in mind that some features that you’re going to use in your scripts could not be implemented on some devices/browsers.

To better understand the concept let’s take an example. Let’s say that you’re going to use geolocation on your website.

		navigator.geolocation.getCurrentPosition(locationHandler);
	

The above could be one option. But what happens if the user browser does not support geolocation. Your website will break and offer a poor user experience.
By simply adding an if you’re out of the trouble.

		if (navigator.geolocation)
			navigator.geolocation.getCurrentPosition(locationHandler);
	

You can even have some fail-over mechanism implemented on else branch. As I said nothing complicated, only a mindset change. Develop for the highest end browsers/devices, but think of all.

The same can be applied to CSS. If you want to implement CSS gradients you will have to do something like

		background-color: #00ff00;
		background-image: url(bg.jpg);
		background-image: url(bg.jpg), -moz-linear-gradient(90deg, #00ff00, #0000ff);
		background-image: url(bg.jpg), -webkit-gradient(linear, 0% 0%, 0% 100%, from(#00ff00), to(#0000ff));
	

This way you will be able to have a green to blue CSS gradient on both Mozilla and WebKit and just a plain green background on older browsers. Also if you have an image that one will be there as well. The browsers without CSS gradient support will just ignore the last two lines.

Another example will be pagination. If you want to implement a More like functionality (like the one from Facebook news feed) you don’t have to forget about non-Ajax devices and have a next/previous fallback.

Some other examples are JavaScript frameworks that implement features not yet supported on some browsers (read IE here), like Explorer Canvas or CSSPie.

Using progressive enhancements you can offer a better experience for advanced user devices, but without losing the low end ones. Remember that the 80/20 rule applies here as well. 20% of the users generates 80% of the traffic. You don’t want to lose the big amount of traffic, but you also don’t want to lose a big amount of users.

W3C is coming with new techniques to help you in your quest, like media queries. Using an easy syntax you can easily customize your CSS for different device characteristics, like resolution. And the good part is that media queries are becoming widely adopted, even though not fully. Another W3C standard worth to keep in mind for the future, but still draft, is CSS variables.

All these techniques apply mostly to your HTML content, but you should not forget about images. Image optimization is to be done mostly on the server side, after detecting device capabilities.

To be continued …

A short slide presentation on the topic you can find here.

Categories: Web

Just CSS? No way.

September 11, 2012 1 comment

CSS is really a great addition to the present web, but if you’re a developer you would feel like something’s missing. CSS is really helping when it comes to content and layout separation, but on its own, it is not a really powerful language. As a developer you will really feel the need of, at least, things like variables, to make your code easier to maintain.

Built on top of CSS there are two languages, Less and Sass. The basic idea is simple – a language very similar to CSS that features a simple syntax for enabling variables, nested rules, rule inheritance and many other nice features. And using some kind of compiler, you are able to generate a CSS file based on one or multiple source files.

Less

I initially used Less. Huge improvement over CSS. At least you had variables and you could organize your elements better. You want to modify a color, a font size or a padding, you just modify one variable in one place and you have all your buttons, links, lists, in one word all your components updated to the new style. The days where you just scan through the code to find that color are gone.

I don’t know about you, but in CSS I find it very hard to organize my rules. But now I have nested rules and even rule inheritance. And if we came to the code structure part, CSS imports are helping a lot. But there’s a problem with these imports: different CSS files – different requests. And you don’t want 4-5 requests in your page just for the styles. Usually you want just one. And that’s very easy now, as imports are made compile time and all your styles are combined into one.

SASS/SCSS

And now that you tasted all these things, you would want the next level. What about loops and conditional blocks (if statement)? And then I switched to SASS, which has all these features and whatever Less is bringing to the table. Actually I switched to SCSS. Because I personally don’t like languages like Haml – too error prone. And SASS is such a language. But not SCSS, with a very alike CSS syntax.

Some tips – How to organize your content

I find it very useful to have the following files

reset.less/.scss
a general reset file used to bring all browsers to a common ground
elements.less/.scss
a file containing all the global variable definitions, like button colors, heading sizes etc.
shared.less/.scss
a file that will contain CSS rules that will span across all your web site sections; then you can have a file for each section that will import this one

Conclusions

Of course, Sass/Scss has its limitations as well, but it’s a huge step from CSS. Amongst its main limitations I would remember: no recursion on mixins (which are similar to procedures/functions), limited set of functions for working with lists, there’s no way to define custom functions outside Ruby.

In this light, I can say that CSS on its own is obsolete, unless it will be extended with features like the ones above. In a future article I will come back and present how to integrate Sass with Maven and Eclipse.

Categories: Web

DomELResolver

September 6, 2012 Leave a comment

Starting with JSP 2.1 there is a very nifty feature: ELResolvers. Even there’s a little less popular, it can make your code nice and clean.
It is well known, that scriptlets are a no-go for JSP development. As an alternative, you can use custom tags and expression language. The nice thing about EL is that it is easily extensible. You can define custom functions, using tag library descriptors, and through resolver, you can plugin bean property resolution.

Now I’ll walk you through a full blown example of working with ELResolvers.

I don’t know if you ever had to work with XML documents inside your JSP, but the options aren’t so good and in the end your code will look ugly, either you use scriptlets (totally not recommended), complex custom tags or custom functions. I acknowledged that XML/DOM processing should happen mostly on the controller side (servlet, Spring controller or other), but there are times when you need it on JSP, like some kind of transcoder functionality.
JSTL offers a set of tags for XML processings. Still feels a little bit hard to work with. Just imagine you would have to use the value of an XPath into an attribute.

<x:set var="title" select="$doc//title"/>
${title}

It would be nice if you could do it directly: ${doc["//title"]}. And now we get to the EL Resolver. It practically instructs EL engine how to evaluate a property for a bean.

Implement an EL Resolver

As the code will tell better the story, here it is.

import java.beans.FeatureDescriptor;
import java.util.ArrayList;
import java.util.Iterator;

import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ELResolver;

import org.jaxen.JaxenException;
import org.jaxen.XPath;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class DomELResolver extends ELResolver {

	@Override
	public Class<?> getCommonPropertyType(ELContext context, Object base) {
		if (base instanceof NodeList)
			return Integer.class;
		return String.class;
	}

	@Override
	public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base) {
		return null;
	}

	@Override
	public Class<?> getType(ELContext context, Object base, Object property) {
		return getValue(context, base, property).getClass();
	}

	@Override
	public Object getValue(ELContext context, Object base, Object property) {
		if (property == null) {
			return null;
		}
		// get the property as a string
		String propertyAsString = property.toString();
		
		if (base instanceof ListOfNodes) {
			// if the base object is a list of nodes, the property must be an index
			int index = getPropertyAsIndex(property);
			if (index >= 0) {
				if (context != null) {
					context.setPropertyResolved(true);
				}
				return ((ListOfNodes)base).get(index);
			} else {
				base = ((ListOfNodes)base).get(0);
			}
		}
		
		if (base instanceof NodeList && !(base instanceof Node)) {
			// if the base object is a DOM NodeList, the property must be an index
			int index = getPropertyAsIndex(property);
			if (index >= 0) {
				if (context != null) {
					context.setPropertyResolved(true);
				}
				return ((NodeList)base).item(index);
			} else {
				base = ((NodeList)base).item(0);
			}
		}
		
		if (base instanceof Node) {
			Node baseNode = (Node)base;
			
			// if the property contains special characters, it is most probably an XPath expression
			if (!containsOnlyAlphaNumeric(propertyAsString)) {
				try {
					// creates the XPath expression and evaluates it
					XPath xpath = new org.jaxen.dom.DOMXPath(propertyAsString);
				    ListOfNodes l = new ListOfNodes();
				    for (Object result : xpath.selectNodes(base)) {
				    	if (result instanceof Node) {
				    		l.add((Node)result);
				    	}
				    }
				    // if we found a node then we consider the expression resolved
				    if (!l.isEmpty()) {
						if (context != null) {
							context.setPropertyResolved(true);
						}
						return l;
				    }
				    return null;
				} catch (JaxenException exc) {
					throw new ELException("Cannot compile XPath.", exc);
				}
				
			}
			
			// if the base bean is a node and has children, then get the children of which tag name is
			// the same as the given property
			if (hasChildElements(baseNode)) { 				
				ListOfNodes c = getChildrenByTagName(baseNode, propertyAsString);
				if (c != null) {
					if (context != null) {
						context.setPropertyResolved(true);
					}
					return c;
				}
			}
		}
		
		// evaluates the expression to an attribute of the base element
		if (base instanceof Element) {
			Element el = (Element) base;
			if (el.hasAttribute(propertyAsString)) {
				if (context != null) {
					context.setPropertyResolved(true);
				}
				return el.getAttribute(propertyAsString);
			}
		}
		
		return null;
	}

	@Override
	public boolean isReadOnly(ELContext context, Object base, Object property) {
		// we cannot modify the DOM
		return true;
	}

	@Override
	public void setValue(ELContext context, Object base, Object property, Object value) {
		// we don't modify the DOM
		return;
	}
	
	/**
	 * @param property the EL property 
	 * @return the property as an integer, -1 if the property is not a number 
	 */
	private int getPropertyAsIndex(Object property) {
		int index = -1;
		if (property instanceof Number) {
			index = ((Number)property).intValue();
		} else if (property instanceof String) {
			try {
				index = Integer.parseInt(property.toString());
			} catch (NumberFormatException exc) {
			}
		}
		return index;
	}
	
	/**
	 * @param s the string to be tested
	 * @return true if the given string contains only alphanumeric characters, false otherwise
	 */
	private boolean containsOnlyAlphaNumeric(String s) {
		for (int i = 0, n = s.length(); i < n; i++) {
			if (!Character.isLetterOrDigit(s.codePointAt(i))) {
				return false;
			}
		}
		return true;
	}
	
	/**
	 * @param el the element to search for children with a given tag name
	 * @param tagChildName the tag name 
	 * @return the first element with the given tag name
	 */
	private ListOfNodes getChildrenByTagName(Node el, String tagChildName) {
		ListOfNodes l = new ListOfNodes();
		NodeList children = el.getChildNodes();
		for (int i = 0, n = children.getLength(); i < n; i++) {
			Node c = children.item(i);
			if (c instanceof Element) {
				Element ce = (Element)c;
				if (tagChildName.equals(ce.getTagName())) {
					l.add(ce);
				}
			}
		}
		return l.isEmpty() ? null : l;
	}

	/**
	 * @param el the DOM element
	 * @return true if the given DOM element has at least one children element, false otherwise
	 */
	private boolean hasChildElements(Node el) {
		NodeList children = el.getChildNodes();
		for (int i = 0, n = children.getLength(); i < n; i++) {
			if (children.item(i) instanceof Element) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Encapsulates a list of nodes to give EL the opportunity to work with as with a normal collection.
	 * Also it evaluates to a string, as the first node text content.
	 */
	@SuppressWarnings("serial")
	private static class ListOfNodes extends ArrayList<Node> {
		@Override
		public String toString() {
			return get(0).getTextContent();
		}
	}
	
}

This entire code practically instructs EL engine how to evaluate on a DOM element a property, either to a child tag name or to an XPath.

Register an EL Resolver

Before using it, you need to register your resolver. The below code does this and you can put it into a ServletContextListener, a ServletContextAware Spring bean or other kind of method that registers it at the application statup.

Using a ServletContextAware bean
import javax.el.ELResolver;
import javax.servlet.ServletContext;
import javax.servlet.jsp.JspApplicationContext;
import javax.servlet.jsp.JspFactory;

import org.springframework.web.context.ServletContextAware;

/** Registers the specified ELResolver's in the JSP EL context. */
public class ELResolversRegistrar implements ServletContextAware {

	/**
	 * The EL resolvers to be registered.
	 */
	private ELResolver[] resolvers;
	
	/** 
	 * Creates a registrar with the given resolvers.
	 * @param resolvers the EL resolvers to be registered 
	 */
	public ELResolversRegistrar(ELResolver... resolvers) {
		this.resolvers = resolvers;
	}

	/** 
	 * Creates a registrar with the given resolver.
	 * @param resolver the EL resolver to be registered 
	 */
	public ELResolversRegistrar(ELResolver resolver) {
		this(new ELResolver[]{resolver});
	}

	public void setServletContext(ServletContext servletContext) {
        JspApplicationContext jspContext = JspFactory.getDefaultFactory().getJspApplicationContext(servletContext);
        for (ELResolver resolver : resolvers) {
        	jspContext.addELResolver(resolver);
        }
	}
}

and the code in the Spring context XML

	<bean class="ELResolversRegistrar">
		<constructor-arg>
			<bean class="DomELResolver"/>
		</constructor-arg>
	</bean>
Using a ServletContextListener
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.jsp.JspApplicationContext;
import javax.servlet.jsp.JspFactory;

public class DomELResolverRegistrarListener implements ServletContextListener {

	public void contextInitialized(ServletContextEvent sce) {
        JspApplicationContext jspContext = JspFactory.getDefaultFactory()
        		.getJspApplicationContext(sce.getServletContext());
       	jspContext.addELResolver(new DomELResolver());
	}

	public void contextDestroyed(ServletContextEvent sce) {
		// do nothing
	}

}

and in web.xml

	<listener>
		<listener-class>DomELResolverRegistrarListener</listener-class>
	</listener>

It is obvious why I prefer the first version: easy extensible and you can have only one registrar class for multiple resolvers.

And in the end some examples how you can use the resolver in a JSP

Use an EL Resolver

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
<x:parse varDom="doc">
<html>
<head>
	<title>Hello</title>
</head>
<body>
	<ul>
		<li>Item 1</li>
		<li>Item 2</li>
	</ul>
</body>
</html>
</x:parse>
 
Title: ${doc.html.head.title} = ${doc["//title"]}

<br/>
Items: 
<c:forEach var="i" items="${doc.html.body.ul.li}">
 	${i.textContent}
</c:forEach>
 
<br/>
First item: ${doc.html.body.ul.li}

You can modify the resolver to even evaluate CSS selectors. But that’s your homework. Or a future story.

Categories: Software Tags: ,
Follow

Get every new post delivered to your Inbox.