{"id":35,"date":"2006-06-06T20:30:24","date_gmt":"2006-06-07T03:30:24","guid":{"rendered":"https:\/\/dubinko.info\/blog\/2006\/06\/06\/microformat-validation-with-python-and-xpath\/"},"modified":"2006-06-06T20:32:36","modified_gmt":"2006-06-07T03:32:36","slug":"microformat-validation-with-python-and-xpath","status":"publish","type":"post","link":"https:\/\/dubinko.info\/blog\/2006\/06\/microformat-validation-with-python-and-xpath\/","title":{"rendered":"Microformat validation with Python and XPath"},"content":{"rendered":"<p>Python+XPath is a surprisingly powerful combination for doing all kinds of arbitrary validation tasks. <a href=\"http:\/\/xformsinstitute.com\/validator\/\">I should know<\/a>. I&#8217;ve recently figured out a few things that make it even better.<\/p>\n<p><strong>Line numbers in error messages.<\/strong> Libxml2 docs aren&#8217;t exactly forthcoming in this area. It&#8217;s pretty easy to register an error callback, but maddeningly it doesn&#8217;t include line numbers (except when piping errors directly to stdout, as several examples show). The C APIs have a whole notion of Structured Error Handling, which doesn&#8217;t seem to come across to the Python bindings. Getting the line number of a node is also straightforward, but I couldn&#8217;t figure out how to get the line of an <em>error<\/em>. Fortunately, the answer is simple:<\/p>\n<blockquote>\n<pre>e = libxml2.lastError()\r\nprint e.line()  # in contrast to node.lineNo()...<\/pre>\n<\/blockquote>\n<p><strong>Checking for a class.<\/strong> Another common task in validating microformats is checking whether an element has a certain class applied to it. Since the class attribute takes a space-separated list of class values, this is harder than string search&#8211;you really need a tokenizer. Again, Python Libxml2 comes through. It&#8217;s reasonably simple to write an XPath extension function in Python:<\/p>\n<blockquote>\n<pre>def hasClass(ctx, content, cssclass):\r\nrc = \"\"\r\nif (isinstance(content, str):\r\ntokens = content.split()\r\nfor token in tokens:\r\nif token==cssclass: rc = \"1\"\r\nreturn rc\r\n\r\n# register the function on an XPath context (ctx)\r\nctx.registerXPathFunction(\"hasClass\", \"http:\/\/some.uri\", hasClass)<\/pre>\n<\/blockquote>\n<p>(WordPress keeps eating the indentation on the above&#8230;you&#8217;ll figure it out.) Props to Kimbro Staken who did all the initial <a title=\"libxslt Extension Functions in Python\" href=\"http:\/\/www.xmldatabases.org\/movabletype\/archives\/000291.html\">hard<\/a> <a title=\"Writing libxslt extension modules in Python\" href=\"http:\/\/www.xmldatabases.org\/WK\/blog\/1274?t=item\">work<\/a>. Comments? -m<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Python+XPath is a surprisingly powerful combination for doing all kinds of arbitrary validation tasks. I should know. I&#8217;ve recently figured out a few things that make it even better. Line numbers in error messages. Libxml2 docs aren&#8217;t exactly forthcoming in this area. It&#8217;s pretty easy to register an error callback, but maddeningly it doesn&#8217;t include&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[5],"tags":[],"class_list":["post-35","post","type-post","status-publish","format-standard","hentry","category-microformats"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p8eo8l-z","_links":{"self":[{"href":"https:\/\/dubinko.info\/blog\/wp-json\/wp\/v2\/posts\/35","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dubinko.info\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dubinko.info\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dubinko.info\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dubinko.info\/blog\/wp-json\/wp\/v2\/comments?post=35"}],"version-history":[{"count":0,"href":"https:\/\/dubinko.info\/blog\/wp-json\/wp\/v2\/posts\/35\/revisions"}],"wp:attachment":[{"href":"https:\/\/dubinko.info\/blog\/wp-json\/wp\/v2\/media?parent=35"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dubinko.info\/blog\/wp-json\/wp\/v2\/categories?post=35"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dubinko.info\/blog\/wp-json\/wp\/v2\/tags?post=35"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}