Dealing with unqualified HREF values

When I was building my extension for finding unused CSS rules, I needed a way of qualifying any href value into a complete URI. I needed this because I wanted it to support stylesheets inside IE conditional comments, but of course to Firefox these are just comments — I had to parse each comment node with a regular expression to extract what’s inside it, and therefore, the href value I got back was always just a string, not a property or a qualified path.

And it’s not the first time I’ve needed this ability, but in the past it’s been with predictable circumstances where I already know the domain name and path. But here those circumstances were not predictable — I needed a solution that would work for any domain name, any path, and any kind of href format (remembering that an href value could be any one of several formats):

  • relative: "test.css"
  • relative with directories: "foo/test.css"
  • relative from here: "./test.css"
  • relative from higher up the directory structure: "../../foo/test.css"
  • relative to the http root: "/test.css"
  • absolute: ""
  • absolute with port: ""
  • absolute with different protocol: ""

When are HREFs qualified?

When we retrieve an href with JavaScript, the value that comes back has some cross-browser quirks. What mostly happens is that a value retrieved with the shorthand .href property will come back as a qualified URI, whereas a value retrieved with getAttribute('href') will (and should, according to specification) come back as the literal attribute value. So with this link:

<a id="testlink" href="/test.html">test page</a>

We should get these values:

document.getElementById('testlink').href == ''; document.getElementById('testlink').getAttribute('href') == '/test.html';

And in Opera, Firefox and Safari that is indeed what we get. However in Internet Explorer (all versions, up to and including IE7) that isn’t what happens — for both examples we get back a fully-qualified URI, not a raw attribute value:

document.getElementById('testlink').href == ''; document.getElementById('testlink').getAttribute('href') == '';

This behavioral quirk is documented in Kevin Yank and Cameron Adams’ recent book, Simply JavaScript; but it gets quirkier still. Although this behavior applies with the href of a regular link (an <a> element), if we do the same thing for a <link> stylesheet, we get exactly the opposite behavior in IE. This HTML:

<link rel="stylesheet" type="text/css" href="/test.css" />

Produces this result:

document.getElementById('teststylesheet').href == '/test.css'; document.getElementById('teststylesheet').getAttribute('href') == '/test.css';

In both cases we get the raw attribute value (whereas in other browsers we get the same results as for an anchor — .href is fully qualified while getAttribute produces a literal value).


Behavioral quirks aside, I have to say that IE‘s behavior with links is almost always what I want. Deriving a path or file name from a URI is fairly simple, but doing the opposite is rather more complex.

So I wrote a helper function to do it. It accepts an href in any format and returns a qualified URI based on the current document location (or if the value is already qualified, it’s returned unchanged):

//qualify an HREF to form a complete URI function qualifyHREF(href) {     //get the current document location object  var loc = document.location;    //build a base URI from the protocol plus host (which includes port if applicable)  var uri = loc.protocol + '//' +;   //if the input path is relative-from-here   //just delete the ./ token to make it relative  if(/^(./)([^/]?)/.test(href))   {       href = href.replace(/^(./)([^/]?)/, '$2');  }   //if the input href is already qualified, copy it unchanged     if(/^([a-z]+):///.test(href))   {       uri = href;     }   //or if the input href begins with a leading slash, then it's base relative     //so just add the input href to the base URI    else if(href.substr(0, 1) == '/')   {       uri += href;    }   //or if it's an up-reference we need to compute the path    else if(/^((../)+)([^/].*$)/.test(href))    {       //get the last part of the path, minus up-references        var lastpath = href.match(/^((../)+)([^/].*$)/);        lastpath = lastpath[lastpath.length - 1];       //count the number of up-references         var references = href.split('../').length - 1;          //get the path parts and delete the last one (this page or directory)       var parts = loc.pathname.split('/');        parts = parts.splice(0, parts.length - 1);          //for each of the up-references, delete the last part of the path       for(var i=0; i<references; i++)      {           parts = parts.splice(0, parts.length - 1);      }       //now rebuild the path      var path = '';      for(i=0; i<parts.length; i++)        {           if(parts[i] != '')          {               path += '/' + parts[i];             }       }       path += '/';        //and add the last part of the path         path += lastpath;       //then add the path and input href to the base URI      uri += path;    }   //otherwise it's a relative path,   else    {       //calculate the path to this directory      path = '';      parts = loc.pathname.split('/');        parts = parts.splice(0, parts.length - 1);      for(var i=0; i<parts.length; i++)        {           if(parts[i] != '')          {               path += '/' + parts[i];             }       }       path += '/';        //then add the path and input href to the base URI      uri += path + href;     }   //return the final uri  return uri; }

One more for the toolkit!


Category: javascript Time: 2007-08-10 Views: 1

Related post

  • Dealing with unqualified HREF values (Part 2) 2007-10-17

    In my original blog post, Dealing with unqualified HREF values, I put forward a method for converting an href value in any format into a fully-qualified URL, using data from the document location object. However, as one commentator pointed out, the p

  • Dealing with Many Meta Values, 30+ 2014-05-09

    I have a "Listing" post type with 30+ meta keys which I feel like can cause a strain on the database when there's 100+ posts. Usually what I do is save each meta value 1 by 1 like so: if(isset($_POST['_item_stock']) && !empty($_POST['_it

  • How to deal with LDAP attribute values having $ in them 2012-02-09

    Just beginning with LDAP and have imported outlook records into a directory. that look like this: Have also edited individual addresses in in the Apache Directory Studio any number of ways to show the street, and city, state on separate lines like a

  • Need to remove href values when printing in Chrome 2011-09-04

    I'm attempting to customize the print CSS, and finding that it prints links out with the href value as well as the link. This is in Chrome. For this HTML: <a href="">Google</a> It prints: Google (http://www.googl

  • Dealing with management that does not see value in improvements that are not immediately visible to the user 2012-02-01

    I can understand schedule pressure. You want to please your users, as they are the lifeblood of the company. However, it is also true that certain changes will make everything easier down the road. Unfortunately, management in my organization has an

  • How do you deal with very long dropdown values? 2012-12-20

    Usually, dropdown menus are made as long as their longest value. However, that works well only for dropdowns with a predefined set of values. How can we deal with a dropdown that receives its values dynamically and displays user-generated values whic

  • How to deal with raw values and percentages? 2014-05-12

    What is the standard practice for dealing with attribute modifiers in games where units have attributes, such as RTSs, MOBAs and RPGs? Specifically, in which order are "buffs" given to the unit? Suppose the case where unit X has 10 blah-points (

  • Dealing with joins in persistent key-value stores 2015-07-11

    One promising emerging category of NoSQL databases is key-value stores. These include Redis (disk-backed), Riak, Aerospike and others. The problem I struggle with the most is the lack of joins. Consider a weather application, which would need to stor

  • Dealing with Null Values in Destination Table After Editing with ArcGIS Relationship Class? 2015-08-04

    I have an ArcGIS geodatabase that contains one origin feature class linked to multiple standalone tables by Simple one-to-many Relationship Classes. The foreign keys in the destination tables are all nullable, deliberately, in order to allow shapes i

  • Dealing with char values over 127 in C 2016-02-04

    I'm quite new to C programming, and I have some problems trying to assign a value over 127 (0x7F) in a char array. In my program, I work with generic binary data and I don't face any problem printing a previously acquired byte stream (e.g. with fopen

  • Dealing with -0 values in a numpy array 2016-02-15

    For some reason, my data reduction for a fits image has given me -0 values, which I would like to set to 0. I've attempted to use: my_array[~numpy.isfinite(my_array)] = 0 All I would like to do is set the -0 values in the corrfact_um2_ext1 array to 0

  • How to set href value by list with forloop.counter0 as index? 2016-02-15

    I am passing list called 'list' to view and i want to create links with href attribute as value of list element iterated by forloop.counter0. As far as I know getting list element requires such code : {{ list.0 }} But how can I iterate with forloop.c

  • how to deal with foreign keys with fixed values (on a db-table-basis) 2012-12-19

    I have a control table that looks like this: CREATE TABLE `tbl_control` ( `tm_db_tbl` varchar(64) NOT NULL, `tm_key` int(11) unsigned NOT NULL, /* a bunch of other fields here */ PRIMARY KEY (`tm_db_tbl`,`tm_key`) ) ENGINE=InnoDB DEFAULT CHARSET=lati

  • Mapserver, TMS, Scales zoom levels and how to deal with all of it 2011-06-12

    I have a whole bunch of data in my db that I need to draw at different zoom levels using Mapserver. Everything uses a 4326 SRID. My (custom) client, will fetch the data using 20 TMS zoom levels and images of 256x256 pixels. In fact, for every zoom le

  • Website "theft" - what is the best way of dealing with these individuals? 2013-07-15

    I was doing a duplicate content search on the web for our site content and found that someone has downloaded/mirrored our entire website and is hosting it on a subdomain of their own main domain. When I check the WHOIS database, no details of the use

  • Update URL with new parameter value 2015-03-05

    I needed a way to update a parameter in the URL, or add it if it doesn't exist, but keep any other variables the same value. I built this function to do the task, and while it works, I feel like it's taking longer than it should. Does anyone have any

  • IT Considerations for Web Application Dealing with Online Payments? 2009-05-27

    I'm starting a project in which certain users will be giving their credit card numbers for online payments. I know how to deal with the web-application side of things, however I would like to get advice about what should be the IT considerations of m

  • C++ Convert String with commas separated values to vector int 2009-07-13

    I need to load and use CSV file data in C++. At this point it can really just be a comma-delimited parser (ie don't worry about escaping new lines and commas). The main need is a line-by-line parser that will return a vector for the next line each ti

  • General: Best way to deal with cleartext password? Specific: Cygwin/email/bash 2009-10-28

    I'm setting up Cygwin, and one of the packages I'm using is 'email' for, what else, sending e-mail from a script. I've "improved" one of my concerns about email's configuration, by copying /etc/email/email.conf to a directory within my home dire

iOS development

Android development

Python development

JAVA development

Development language

PHP development

Ruby development


Front-end development


development tools

Open Platform

Javascript development

.NET development

cloud computing


Copyright (C), All Rights Reserved.

processed in 1.163 (s). 13 q(s)