Hi Mads,
In HXT, namespace prefixes bound by an XML document are valid in the context of an XPath. How do avoid that?
An example program will clarify:
simpleXml :: String simpleXml = "<soap:Body xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\"/>"
nsEnv :: [(String, String)] nsEnv = [ ("s" , "http://www.w3.org/2003/05/soap-envelope") ]
evalXPath :: String -> String -> [XmlTree] evalXPath xpath xml = runLA ( xread >>> propagateNamespaces >>> getXPathTreesWithNsEnv nsEnv xpath ) xml
Here:
evalXPath "//s:Body" simpleXml == evalXPath "//soap:Body" simpleXml
Even though I only mentions the prefix "s" (and not "soap") in the function nsEnv.
When working with namespaces in XML, the prefixes are not longer significant. After namespace propagation every name in the XML document is identified by a qualified name. This is a pair consisting of the namespace URI and the local part. The prefixes become irrelevant. A namespace aware XPath expression needs a namespace environment, as given in the example, to construct these qualified names for the names in the XPath expression. So the results of both evalXPath calls in your example must be the same.
I do not want the XPath to see prefixes declared in the xml-document, as it means that two semantically similar XML documents can get different results when applied to the same XPath.
If you intend, that the prefixes are significant, then you should not work with namespace propagation. If namespaces are not propagated, all names occurring in the document are taken as they are. That means "s:Body" is different from "soap:Body". For solving your tasks there could be 2 ways: 1. don't use namespaces, no propagateNamespaces, no getXPathTreesWithNsEnv, use the prefixes instead. Disadvantage: the prefixes become significant. If prefixes change, the semantics changes. 2. Use propagateNamespaces and getXPathTreesWithNsEnv, but select all nodes via the namespace URIs, not via the prefixes. If you want to output the manipulated XML parts and use standard prefixes for the namespaces, then use the namespace manipulation functions in http://hackage.haskell.org/packages/archive/hxt/latest/doc/html/Text-XML-HXT... Cheers, Uwe
Hi Uwe I read your reply multiple times, but I am still confused. I think either I misunderstand you or I did not explain myself properly in the first mail.
Hi Mads,
In HXT, namespace prefixes bound by an XML document are valid in the context of an XPath. How do avoid that?
An example program will clarify:
simpleXml :: String simpleXml = "<soap:Body xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\"/>"
nsEnv :: [(String, String)] nsEnv = [ ("s" , "http://www.w3.org/2003/05/soap-envelope") ]
evalXPath :: String -> String -> [XmlTree] evalXPath xpath xml = runLA ( xread >>> propagateNamespaces >>> getXPathTreesWithNsEnv nsEnv xpath ) xml
Here:
evalXPath "//s:Body" simpleXml == evalXPath "//soap:Body" simpleXml
Even though I only mentions the prefix "s" (and not "soap") in the function nsEnv.
When working with namespaces in XML, the prefixes are not longer significant. After namespace propagation every name in the XML document is identified by a qualified name. This is a pair consisting of the namespace URI and the local part. The prefixes become irrelevant.
This is my point. Prefixes are relevant in the current implementation of HXT.
A namespace aware XPath expression needs a namespace environment, as given in the example, to construct these qualified names for the names in the XPath expression. So the results of both evalXPath calls in your example must be the same.
Yes, but in the namespace environment I give to getXPathTreesWithNsEnv I only mention the prefix s, yet I am still able to evaluate the xpath "//soap:Body". Furthermore "//s:body" and "//soap:Body" gives the same results. Why? I think another example will clarify my point. The code: simpleXmlOne, simpleXmlTwo :: String simpleXmlOne = "<a:Foo xmlns:a=\"http://foo.org\"/>" simpleXmlTwo = "<b:Foo xmlns:b=\"http://foo.org\"/>" nsEnv :: [(String, String)] nsEnv = [ ("notFoo" , "http://notfoo.org") ] evalXPath :: String -> [XmlTree] evalXPath xml = runLA ( xread >>> propagateNamespaces >>> getXPathTreesWithNsEnv nsEnv "//a:Foo" ) xml Now notice that simpleXmlOne and simpleXmlTwo are equivalent. Yes, they have a different prefix for "http://foo.org", but the documents means the same. And as you write yourself, "... the prefix is no longer releavant ..." Yet: evalXPath simpleXmlOne /= evalXPath simpleXmlTwo Hope that clarifies things. Regards, Mads
Hi Replying to myself:
I think another example will clarify my point. The code:
simpleXmlOne, simpleXmlTwo :: String simpleXmlOne = "<a:Foo xmlns:a=\"http://foo.org\"/>" simpleXmlTwo = "<b:Foo xmlns:b=\"http://foo.org\"/>"
nsEnv :: [(String, String)] nsEnv = [ ("notFoo" , "http://notfoo.org") ]
evalXPath :: String -> [XmlTree] evalXPath xml = runLA ( xread >>> propagateNamespaces >>> getXPathTreesWithNsEnv nsEnv "//a:Foo" ) xml
Now notice that simpleXmlOne and simpleXmlTwo are equivalent. Yes, they have a different prefix for "http://foo.org", but the documents means the same. And as you write yourself, "... the prefix is no longer releavant ..." Yet:
evalXPath simpleXmlOne /= evalXPath simpleXmlTwo
Just to clarify things. The point I am making is that: getXPathTreesWithNsEnv nsEnv "//a:Foo" do not only see the prefixes in 'nsEnv', but also the prefixes in the XML it is applied to. I think that the getXPathTreesWithNsEnv function should only see the prefixes mentioned in its first parameter. Regards, Mads
Hi Mads,
Replying to myself:
I think another example will clarify my point. The code:
simpleXmlOne, simpleXmlTwo :: String simpleXmlOne = "<a:Foo xmlns:a=\"http://foo.org\"/>" simpleXmlTwo = "<b:Foo xmlns:b=\"http://foo.org\"/>"
nsEnv :: [(String, String)] nsEnv = [ ("notFoo" , "http://notfoo.org") ]
evalXPath :: String -> [XmlTree] evalXPath xml = runLA ( xread >>> propagateNamespaces >>> getXPathTreesWithNsEnv nsEnv "//a:Foo"
this line contains the problem: getXPathTreesWithNsEnv assumes, that for all prefixes used in the XPath expr, the nsEnv contains an entry. Furthermore the default namespace can be given by an entry for the empty prefix "". So you'll only get reasonable results, when nsEnv contains at least an entry for "a", e.g. nsEnv = [ ("a", "http://x.y"), ... ] when you use the XPath expr "//a:Foo". You may argue, that in your example, an error should be raised by the XPath parser, instead of accepting "//a:Foo". But currently it's assumed, that getXPathTreesWithNsEnv is used only in an innocent way. Cheers, Uwe
On 7 April 2010 16:41, Uwe Schmidt <si@fh-wedel.de> wrote:
But currently it's assumed, that getXPathTreesWithNsEnv is used only in an innocent way.
I like your phrasing here... I might steal it for graphviz rather than just saying "it's assumed that you don't do such-and-such" :p -- Ivan Lazar Miljenovic Ivan.Miljenovic@gmail.com IvanMiljenovic.wordpress.com
Hi Uwe
Hi Mads,
Replying to myself:
I think another example will clarify my point. The code:
simpleXmlOne, simpleXmlTwo :: String simpleXmlOne = "<a:Foo xmlns:a=\"http://foo.org\"/>" simpleXmlTwo = "<b:Foo xmlns:b=\"http://foo.org\"/>"
nsEnv :: [(String, String)] nsEnv = [ ("notFoo" , "http://notfoo.org") ]
evalXPath :: String -> [XmlTree] evalXPath xml = runLA ( xread >>> propagateNamespaces >>> getXPathTreesWithNsEnv nsEnv "//a:Foo"
this line contains the problem:
getXPathTreesWithNsEnv assumes, that for all prefixes used in the XPath expr, the nsEnv contains an entry. Furthermore the default namespace can be given by an entry for the empty prefix "".
So you'll only get reasonable results, when nsEnv contains at least an entry for "a", e.g.
nsEnv = [ ("a", "http://x.y"), ... ]
when you use the XPath expr "//a:Foo".
You may argue, that in your example, an error should be raised by the XPath parser, instead of accepting "//a:Foo". But currently it's assumed, that getXPathTreesWithNsEnv is used only in an innocent way.
Yes, that was what I would have expected.
Cheers,
Uwe
/Mads
participants (3)
-
Ivan Miljenovic -
Mads Lindstrøm -
Uwe Schmidt