[XML-SIG] Using XML Namespaces in XPath Expressions from Python

JonTom Kittredge jontom at itasoftware.com
Mon Jun 13 16:29:45 CEST 2005


Uche, Thanks for your response. My comments are below.


On 2005-06-09 at 06:26, Uche Ogbuji wrote:
>  On Wed, 2005-06-08 at 10:27 -0400, JonTom Kittredge wrote:
>  > I'm having trouble using PyXML to evaluate XPath expressions that
>  > include namespace references.
>  > 
>  > Here is a sample Python snipped:
>  > 
>  >     #!/usr/bin/env pystart
>  > 
>  >     import sys
>  >     import xml.dom.minidom
>  > 
>  >     from xml.xpath.Context import Context
>  >     from xml.xpath import Evaluate
>  >     from xml.xpath.NamespaceNode import NamespaceNode
>  > 
>  > 
>  >     if __name__ == "__main__":
>  >       sys.stderr.write("XPathTest: 18\n")
>  > 
>  >       inputDom = xml.dom.minidom.parse(open("xpathtest-input.xml"))
>  > 
>  >       sys.stderr.write("Node: %s\n" % (inputDom.documentElement))
>  >       outContext = Context(inputDom.documentElement)
>  
>  Where are you passing in the NS mapping here?  Did I miss a PyXML XPath
>  update that defaults mappings to in-scope namespaces on the node passed
>  in?

That's the nub of my question. How do I pass namespace mappings into
Evaluate()? 

The only thing I could see to try, from looking at the documentation,
was to use the context argument. The Context object holds namespace
objects, so I thought that that might be the way to pass in my
definition. 

As you can see from the output, the Context I get from the document
node already has the "dbq" namespace defined (since it appears in the
input), before I call Evaluate(). However, it apparently gets reset
during the call to Evaluate().

>  
>  >       sys.stderr.write("NSes=%s\n" % (outContext.nss()))
>  > 
>  >       result = Evaluate("count(/dbq:Contract)",
>  >                         contextNode=inputDom.documentElement,
>  
>  I think this line is your problem.  It overrides the next (probably not
>  sensible, which is why we reversed that priority in 4Suite ages ago).
>  
>  >                         context=outContext)
>  

OK. If I leave out that line and instead do the following:
    result = Evaluate("count(/dbq:Contract)",
                      contextNode=inputDom.documentElement)


I still get the following error:

Node: <DOM Element: dbq:Contract at 0x82ac2e4>
Traceback (most recent call last):
  File "xpathtest-1.py", line 20, in ?
    contextNode=inputDom.documentElement)
  File "/ita/python-2.2.2/lib/python2.2/site-packages/_xmlplus/xpath/__init__.py", line 70, in Evaluate
    retval = parser.new().parse(expr).evaluate(con)
  File "/ita/python-2.2.2/lib/python2.2/site-packages/_xmlplus/xpath/ParsedExpr.py", line 179, in evaluate
    arg0 = self._arg0.evaluate(context)
  File "/ita/python-2.2.2/lib/python2.2/site-packages/_xmlplus/xpath/ParsedAbsoluteLocationPath.py", line 26, in evaluate
    rt = self._child.select(context)
  File "/ita/python-2.2.2/lib/python2.2/site-packages/_xmlplus/xpath/ParsedStep.py", line 32, in evaluate
    (node_set, reverse) = self._axis.select(context, self._nodeTest.match)
  File "/ita/python-2.2.2/lib/python2.2/site-packages/_xmlplus/xpath/ParsedAxisSpecifier.py", line 114, in select
    list(context.node.childNodes))
  File "/ita/python-2.2.2/lib/python2.2/site-packages/_xmlplus/xpath/ParsedAxisSpecifier.py", line 112, in <lambda>
    rt = filter(lambda node, test=nodeTest, context=context, pt=self.principalType:
  File "/ita/python-2.2.2/lib/python2.2/site-packages/_xmlplus/xpath/ParsedNodeTest.py", line 168, in match
    self._prefix)
xml.xpath.RuntimeException: Undefined namespace prefix: "dbq".

Which me leaves my initial question: how do I use xml.xpath.Evaluate()
on an XPath expression that refers to namespaces?

>  
>  -- 
>  Uche Ogbuji                               Fourthought, Inc.
>  http://uche.ogbuji.net                    http://fourthought.com
>  http://copia.ogbuji.net                   http://4Suite.org
>  Use CSS to display XML, part 2 - http://www-128.ibm.com/developerworks/edu/x-dw-x-xmlcss2-i.html
>  XML Output with 4Suite & Amara - http://www.xml.com/pub/a/2005/04/20/py-xml.html
>  Use XSLT to prepare XML for import into OpenOffice Calc - http://www.ibm.com/developerworks/xml/library/x-oocalc/
>  Schema standardization for top-down semantic transparency - http://www-128.ibm.com/developerworks/xml/library/x-think31.html

For completeness, here is my Python:

    import sys
    import traceback
    import xml.dom.minidom

    from xml.xpath.Context import Context
    from xml.xpath import Evaluate
    from xml.xpath.NamespaceNode import NamespaceNode


    sys.stderr.write("XPathTest: 1\n")

    inputDom = xml.dom.minidom.parse(open("xpathtest-input.xml"))

    sys.stderr.write("Node: %s\n" % (inputDom.documentElement))

    result = Evaluate("count(/dbq:Contract)",
                      contextNode=inputDom.documentElement)
    sys.stderr.write("Eval xpath \"count(/dbq:Contract)\": %d\n" % result)

and here is my input:

    <?xml version="1.0"?>

    <dbq:Contract
        xmlns:dbq="http://dtd.itasoftware.com/Dubuque">
      <dbq:RuleContent/>
    </dbq:Contract>


Yours, JonTom

       JT Kittredge
       ITA Software, Inc.
       Cambridge, Massachusetts


More information about the XML-SIG mailing list