Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for or? #3

Closed
swannodette opened this issue May 6, 2009 · 7 comments
Closed

Support for or? #3

swannodette opened this issue May 6, 2009 · 7 comments

Comments

@swannodette
Copy link
Contributor

I'm actually using Enlive to grab data from Amazon Web Services. One thing that would be nice would be something like the or operator.

[[:some :selector] :or [:another :selector]]

if the first selector returns nodes, that is the result. Otherwise move on to the following selector. This would be useful when some selector for some reason doesn't match and you want to fall back on another selector. This is very useful if you are explicitly using the select macro to pull in portions of an xml document.

@cgrand
Copy link
Owner

cgrand commented May 6, 2009

Github really need to provide some kind of preview feature...
#{[:some :selector] [:another :selector]}

@swannodette
Copy link
Contributor Author

this is the grouping selector though right? I want to shortcut if the first selector matches, does this make sense?

@cgrand
Copy link
Owner

cgrand commented May 7, 2009

Yep, after having slept on it, it occurred to me that what you are asking for is a short-circuiting or. Real short-circuiting is nearly impossible because selection is normally performed on a single pass over the whole tree, and to short-circuit you need to know if the first part of the selector matches something.

I said "normally" because (has xxx) introduce a second selection and, hence, a second pass.

The simplest thing to do is to write a macro on select which outputs:
(let [YYY XXX](or %28seq %28select YYY [:some :selector]%29%29 %28select YYY [:another :selector]%29))

I'm thinking on it.

@cgrand
Copy link
Owner

cgrand commented May 7, 2009

(defn select-else* [nodes & states] ; for completeness only
  (some #(seq (select* nodes %)) states))

(defmacro select-else [nodes & selectors]
  (let [nodes-sym (gensym "nodes")]
    `(let [~nodes-sym ~nodes]
       (or
         ~@(map (fn [sel]
                  `(seq (select ~nodes-sym ~sel)))
             selectors)))))

I tried to think of a (or-else) combinator (to write (or-else [:some :selector] [:another :selector])), it's doable but it really goes against the grain.

Does select-else (or select-else*) do the trick?

@swannodette
Copy link
Contributor Author

(select xml #{[:ASIN], [:title], 
                [:Item :> :MediumImage :URL],
                [:ListPrice :Amount]
                [:ListPrice :FormattedPrice]
                [:Publisher]}

Not really. Here's a real example. [:ListPrice :FormattedPrice] doesn't always match. Sometimes the formatted price appears elsewhere. I want to be able to provide an ordered list of possible selectors and short circuit soon as we find one.

If this isn't possible I can come up with a work around.

For XML data sources that are smart enough not to bother with namespacing all their elements, Enlive is a EXCELLENT tool for extracting data.

(def *aws-base-url* "http://ecs.amazonaws.com/onca/xml")

(def *aws-url-params* {:Service        "AWSECommerceService", 
               :AWSAccessKeyId "AKIAI7BLMMASTXEDYLWA",
               :Operation      "ItemLookup",
               :ResponseGroup  "Medium"})

(defn aws-url [itemid]
  (str *aws-base-url* "?"
       (to-url-params 
    (assoc *aws-url-params* :ItemId itemid))))

(defn amazon-data [itemid]
  (html-resource 
    (java.net.URL. (aws-url itemid))))

(defn item-data [xml]
  (let [item-data (select xml #{[:ASIN], [:title], 
                [:Item :> :MediumImage :URL],
                [:ListPrice :Amount]
                [:ListPrice :FormattedPrice]
                [:Publisher]})]
    (apply hash-map 
       (flatten 
        (map #(vector (:tag %) (:content %)) item-data)))))

(defn amazon-info [itemid]
  (item-data (amazon-data itemid)))

Is all I need to extract info from Amazon on any item. Enlive is a killer app ;)

@cgrand
Copy link
Owner

cgrand commented May 7, 2009

namespace support is on my todo-list.

completely untested (I'll have more time in the afternoon (CEST)):
(defmacro or-else
([sel](selector ~sel))
([sel & sels]
`(sm/union (selector ~sel)
(sm/intersection
(sm/complement-next (has* (selector ~sel1)))
(or-else ~@Sels)))))

(btw in which TZ are you? I thought you were on the east coast)

@cgrand
Copy link
Owner

cgrand commented May 11, 2009

Closing the issue. Performing multiple passes is the way to go.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants