data.zip

Not returning expected result for 'tag='

Details

  • Type: Defect Defect
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Completed
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None
  • Environment:
     :dependencies [[org.clojure/clojure "1.5.1"]
                     [org.clojure/data.zip "0.1.1"]]
  • Patch:
    Code and Test

Description

Setup:

(require '[clojure.xml :as xml])
(require '[clojure.zip :as zip])
(require '[clojure.data.zip.xml :as dzx])

(def s "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<result>\n <status>success</status>\n <message>success</message>\n <format>xml</format>\n <language>en</language>\n <ip>208.67.220.220</ip>\n <country_code>US</country_code>\n <country>United States</country>\n <region>California</region>\n <city>San Francisco</city>\n <latitude>37.7757</latitude>\n <longitude>-122.3952</longitude>\n <zip_code>94107</zip_code>\n <timezone>-08:00</timezone>\n <localtime>2014-04-17 06:52:45</localtime>\n</result>\n")

(def x (xml/parse (org.xml.sax.InputSource. (java.io.StringReader. s))))
(def z (zip/xml-zip x))

Works as expected:

(dzx/xml1-> z :ip dzx/text)
;; "208.67.220.220"

(dzx/xml1-> z :status dzx/text)
;; "success"

Doesn't seem to work as expected:

(dzx/xml1-> z :result)
;; nil   (expected something not nil)

(dzx/xml1-> z :result :status dzx/text)
;; nil   (expected "success")

Activity

Alex Miller made changes -
Field Original Value New Value
Assignee Aaron Bedra [ aaron ] Alex Miller [ alexmiller ]
Alex Miller made changes -
Environment  :dependencies [[org.clojure/clojure "1.5.1"]
                 [uk.org.russet/tawny-owl "1.0"]
                 [clj-http "0.9.1"]
                 [hickory "0.5.3"]
                 [instaparse "1.3.0"]
                 [cheshire "5.3.1"]
                 [org.clojure/data.zip "0.1.1"]]
 :dependencies [[org.clojure/clojure "1.5.1"]
                 [org.clojure/data.zip "0.1.1"]]
Description With this raw data:
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<result>\n <status>success</status>\n <message>success</message>\n <format>xml</format>\n <language>en</language>\n <ip>208.67.220.220</ip>\n <country_code>US</country_code>\n <country>United States</country>\n <region>California</region>\n <city>San Francisco</city>\n <latitude>37.7757</latitude>\n <longitude>-122.3952</longitude>\n <zip_code>94107</zip_code>\n <timezone>-08:00</timezone>\n <localtime>2014-04-17 06:52:45</localtime>\n</result>\n"

And resulting parse/zipper (def _sd ...)
[{:tag :result, :attrs nil, :content [{:tag :status, :attrs nil, :content ["success"]} {:tag :message, :attrs nil, :content ["success"]} {:tag :format, :attrs nil, :content ["xml"]} {:tag :language, :attrs nil, :content ["en"]} {:tag :ip, :attrs nil, :content ["208.67.220.220"]} {:tag :country_code, :attrs nil, :content ["US"]} {:tag :country, :attrs nil, :content ["United States"]} {:tag :region, :attrs nil, :content ["California"]} {:tag :city, :attrs nil, :content ["San Francisco"]} {:tag :latitude, :attrs nil, :content ["37.7757"]} {:tag :longitude, :attrs nil, :content ["-122.3952"]} {:tag :zip_code, :attrs nil, :content ["94107"]} {:tag :timezone, :attrs nil, :content ["-08:00"]} {:tag :localtime, :attrs nil, :content ["2014-04-17 06:52:45"]}]} nil]

The following returns nil:

NS (:require [clojure.data.zip.xml :as dzx])
(dzx/xml1-> _sd (dzx/tag= :result))
(dzx/xml1-> _sd (dzx/tag= :result) (dzx/tag= :status) dzx/text)

But this works:
(dzx/xml1-> _sd (dzx/tag= :ip) dzx/text)
"208.67.220.220"

Setup:

{code}
(require '[clojure.xml :as xml])
(require '[clojure.zip :as zip])
(require '[clojure.data.zip.xml :as dzx])

(def s "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<result>\n <status>success</status>\n <message>success</message>\n <format>xml</format>\n <language>en</language>\n <ip>208.67.220.220</ip>\n <country_code>US</country_code>\n <country>United States</country>\n <region>California</region>\n <city>San Francisco</city>\n <latitude>37.7757</latitude>\n <longitude>-122.3952</longitude>\n <zip_code>94107</zip_code>\n <timezone>-08:00</timezone>\n <localtime>2014-04-17 06:52:45</localtime>\n</result>\n")

(def x (xml/parse (org.xml.sax.InputSource. (java.io.StringReader. s))))
(def z (zip/xml-zip x))
{code}

Works as expected:
{code}
(dzx/xml1-> z :ip dzx/text)
;; "208.67.220.220"

(dzx/xml1-> z :status dzx/text)
;; "success"
{code}

Doesn't seem to work as expected:

{code}
(dzx/xml1-> z :result)
;; nil (expected something not nil)

(dzx/xml1-> z :result :status dzx/text)
;; nil (expected "success")
{code}
Hide
Erik Assum added a comment -

Looking at the definition of tag=
https://github.com/clojure/data.zip/blob/master/src/main/clojure/clojure/data/zip/xml.clj#L26

it does some more logic (which I don’t understand) than both
attr=
https://github.com/clojure/data.zip/blob/master/src/main/clojure/clojure/data/zip/xml.clj#L21

and
text=
https://github.com/clojure/data.zip/blob/master/src/main/clojure/clojure/data/zip/xml.clj#L44

So I’m curious as to why tag= cannot be implemented as:

(defn tag= [tagname]
  (fn [loc]
    (= tagname (:tag (zip/node loc)))))
Show
Erik Assum added a comment - Looking at the definition of tag= https://github.com/clojure/data.zip/blob/master/src/main/clojure/clojure/data/zip/xml.clj#L26 it does some more logic (which I don’t understand) than both attr= https://github.com/clojure/data.zip/blob/master/src/main/clojure/clojure/data/zip/xml.clj#L21 and text= https://github.com/clojure/data.zip/blob/master/src/main/clojure/clojure/data/zip/xml.clj#L44 So I’m curious as to why tag= cannot be implemented as:
(defn tag= [tagname]
  (fn [loc]
    (= tagname (:tag (zip/node loc)))))
Hide
Erik Assum added a comment -

Looking at the definition of tag=
https://github.com/clojure/data.zip/blob/master/src/main/clojure/clojure/data/zip/xml.clj#L26

it does some more logic (which I don’t understand) than both
attr=
https://github.com/clojure/data.zip/blob/master/src/main/clojure/clojure/data/zip/xml.clj#L21

and
text=
https://github.com/clojure/data.zip/blob/master/src/main/clojure/clojure/data/zip/xml.clj#L44

So I’m curious as to why tag= cannot be implemented as:

(defn tag= [tagname]
  (fn [loc]
    (= tagname (:tag (zip/node loc)))))
Show
Erik Assum added a comment - Looking at the definition of tag= https://github.com/clojure/data.zip/blob/master/src/main/clojure/clojure/data/zip/xml.clj#L26 it does some more logic (which I don’t understand) than both attr= https://github.com/clojure/data.zip/blob/master/src/main/clojure/clojure/data/zip/xml.clj#L21 and text= https://github.com/clojure/data.zip/blob/master/src/main/clojure/clojure/data/zip/xml.clj#L44 So I’m curious as to why tag= cannot be implemented as:
(defn tag= [tagname]
  (fn [loc]
    (= tagname (:tag (zip/node loc)))))
Hide
Erik Assum added a comment -

A reason for this would be that the tests fail... but why?

Show
Erik Assum added a comment - A reason for this would be that the tests fail... but why?
Hide
Erik Assum added a comment -

So it seems like the problem is that you get an empty match if you try to match a tag on the first element in the xml:

(def atom2 (parse-str "<feed>
<foo>bar</foo></feed>"))

(deftest dzip-3-first-node
  (is (not= (xml-> atom2 :feed ) '()))) ; fail

(deftest dzip-3-second-node
  (is (= (xml-> atom2 :foo text) '("bar")))) ; pass
Show
Erik Assum added a comment - So it seems like the problem is that you get an empty match if you try to match a tag on the first element in the xml:
(def atom2 (parse-str "<feed>
<foo>bar</foo></feed>"))

(deftest dzip-3-first-node
  (is (not= (xml-> atom2 :feed ) '()))) ; fail

(deftest dzip-3-second-node
  (is (= (xml-> atom2 :foo text) '("bar")))) ; pass
Hide
Erik Assum added a comment - - edited

So, if you do

(def atom2 (parse-str "<feed>
<foo>bar</foo></feed>"))

(deftest dzip-3-first-node
  (is (not= (xml-> (clojure.data.zip/auto false atom2) :feed ) '())))

(deftest dzip-3-second-node
  (is (= (xml-> atom2 :foo text) '("bar"))))

the tests will pass. Whereas if you

(def atom2 (parse-str "<feed>
<foo>bar</foo></feed>"))

(deftest dzip-3-first-node
  (is (not= (xml-> (clojure.data.zip/auto false atom2) :feed ) '())))

(deftest dzip-3-second-node
  (is (= (xml-> (clojure.data.zip/auto false atom2) :foo text) '("bar"))))

zip-3-second-node will fail.

Show
Erik Assum added a comment - - edited So, if you do
(def atom2 (parse-str "<feed>
<foo>bar</foo></feed>"))

(deftest dzip-3-first-node
  (is (not= (xml-> (clojure.data.zip/auto false atom2) :feed ) '())))

(deftest dzip-3-second-node
  (is (= (xml-> atom2 :foo text) '("bar"))))
the tests will pass. Whereas if you
(def atom2 (parse-str "<feed>
<foo>bar</foo></feed>"))

(deftest dzip-3-first-node
  (is (not= (xml-> (clojure.data.zip/auto false atom2) :feed ) '())))

(deftest dzip-3-second-node
  (is (= (xml-> (clojure.data.zip/auto false atom2) :foo text) '("bar"))))
zip-3-second-node will fail.
Erik Assum made changes -
Erik Assum made changes -
Patch Code and Test [ 10002 ]
Hide
Erik Assum added a comment -

The problem was that tag= checked for a match either in the zippers node or in its
children. The patch solves this by first looking for a match in the node,
and if that fails, look for a match in the children.

Show
Erik Assum added a comment - The problem was that tag= checked for a match either in the zippers node or in its children. The patch solves this by first looking for a match in the node, and if that fails, look for a match in the children.
Hide
Alex Miller added a comment -

Thanks, applied for next release!

Show
Alex Miller added a comment - Thanks, applied for next release!
Alex Miller made changes -
Status Open [ 1 ] Closed [ 6 ]
Resolution Completed [ 1 ]

People

Vote (0)
Watch (0)

Dates

  • Created:
    Updated:
    Resolved: