diff --git a/courseware/capa_module.py b/courseware/capa_module.py
index 0948518bb7..28b7f641f7 100644
--- a/courseware/capa_module.py
+++ b/courseware/capa_module.py
@@ -115,7 +115,7 @@ class LoncapaModule(XModule):
dom2 = etree.fromstring(xml)
- self.explanation=content_parser.item(dom2.xpath('/problem/@explain'))
+ self.explanation=content_parser.item(dom2.xpath('/problem/@explain'), default="closed")
self.explain_available=content_parser.item(dom2.xpath('/problem/@explain_available'))
self.due_date=content_parser.item(dom2.xpath('/problem/@due'))
diff --git a/courseware/content_parser.py b/courseware/content_parser.py
index bfeab1db6f..5d91eb8d06 100644
--- a/courseware/content_parser.py
+++ b/courseware/content_parser.py
@@ -11,6 +11,30 @@ course XML file and the rest of the system.
TODO: Shift everything from xml.dom.minidom to XPath (or XQuery)
'''
+def xpath(xml, query_string, **args):
+ ''' Safe xpath query into an xml tree:
+ * xml is the tree.
+ * query_string is the query
+ * args are the parameters. Substitute for {params}. '''
+ doc = etree.fromstring(xml)
+ print type(doc)
+ def escape(x):
+ # TODO: This should escape the string. For now, we just assume it's made of valid characters.
+ # Couldn't figure out how to escape for lxml in a few quick Googles
+ valid_chars="".join(map(chr, range(ord('a'),ord('z')+1)+range(ord('A'),ord('Z')+1)+range(ord('0'), ord('9')+1)))+"_ "
+ for e in x:
+ if e not in valid_chars:
+ raise Exception("Invalid char in xpath expression. TODO: Escape")
+ return x
+
+ args=dict( ((k, escape(args[k])) for k in args) )
+ print args
+ results = doc.xpath(query_string.format(**args))
+ return results
+
+if __name__=='__main__':
+ print xpath('', '/{search}/problem[@name="{name}"]', search='html', name="Bob")
+
def item(l, default="", process=lambda x:x):
if len(l)==0:
return default
diff --git a/settings.py b/settings.py
index 6dd38e683a..f080316198 100644
--- a/settings.py
+++ b/settings.py
@@ -103,6 +103,7 @@ INSTALLED_APPS = (
'django.contrib.humanize',
'static_template_view',
'textbook',
+ 'staticbook',
# Uncomment the next line to enable the admin:
# 'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
diff --git a/urls.py b/urls.py
index d9c0c9801b..dbc5c5ab36 100644
--- a/urls.py
+++ b/urls.py
@@ -19,6 +19,7 @@ urlpatterns = patterns('',
# url(r'^accounts/', include('registration.urls')),
url(r'^t/(?P[^/]*)$', 'static_template_view.views.index'),
url(r'^textbook/(?P[^/]*)$', 'textbook.views.index'),
+ url(r'^book/(?P[^/]*)$', 'staticbook.views.index'),
url(r'^logout$', 'auth.views.logout_user'),
url(r'^login$', 'auth.views.login_user'),
url(r'^login/(?P[^/]*)$', 'auth.views.login_user'),