# HG changeset patch # User Adam Chlipala # Date 1300559711 14400 # Node ID a4e5d053daedee04b63536ddd8dfeef8b7c25a97 # Parent 05a28a77f6feb3a05ce09139d6663338b8a58d60 Preparation for first release diff -r 05a28a77f6fe -r a4e5d053daed LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LICENSE Sat Mar 19 14:35:11 2011 -0400 @@ -0,0 +1,25 @@ +Copyright (c) 2011, Adam Chlipala +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +- The names of contributors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff -r 05a28a77f6fe -r a4e5d053daed src/ur/feed.urs --- a/src/ur/feed.urs Thu Mar 10 18:36:50 2011 -0500 +++ b/src/ur/feed.urs Sat Mar 19 14:35:11 2011 -0400 @@ -1,36 +1,69 @@ +(* This module implements imperative processing of XML feeds. + * + * Module author: Adam Chlipala + *) + con pattern :: Type -> Type -> Type +(* A pattern describes a set of XML subtrees, mapping each element of the set to + * a data value. A value of type [pattern internal result] uses values of type + * [internal] internally, but this API exposes no details of that usage. The + * type [result] gives the type used in mappings of matched subtrees. *) + +val null : pattern unit (variant []) +(* A null pattern matches nothing, returning a value of the impossible empty + * type if it ever does match. *) con tagInternal :: {Unit} -> Type -val null : pattern unit (variant []) - val tag : attrs ::: {Unit} -> folder attrs -> string -> $(mapU string attrs) -> pattern (tagInternal attrs) {Attrs : $(mapU string attrs), Cdata : option string} +(* A basic [tag] pattern matches a single tag with a number of required + * attributes. A result value gives the attribute values and an optional + * CDATA value for the text content of the tag. The [string] argument is the + * tag name, and the following argument gives attribute names. *) val tagA : attrs ::: {Unit} -> folder attrs -> string -> $(mapU string attrs) -> pattern (tagInternal attrs) $(mapU string attrs) +(* A version of [tag] that ignores CDATA *) + val tagAO : attrs ::: {Unit} -> folder attrs -> string -> $(mapU string attrs) -> pattern (tagInternal attrs) $(mapU (option string) attrs) +(* A version of [tagA] that makes each attribute optional *) val tagC : string -> pattern (tagInternal []) string +(* A version of [tag] that only matches tags with nonempty CDATA and returns + * only that text *) con childrenInternal :: Type -> {Type} -> Type val children : parentI ::: Type -> parent ::: Type -> children ::: {(Type * Type)} -> pattern parentI parent -> $(map (fn (i, d) => pattern i d) children) -> folder children -> pattern (childrenInternal parentI (map fst children)) (parent * $(map snd children)) +(* A combinator that takes in a pattern for a parent node and a set of patterns + * that must be matched against children of the parent. This combinator will + * find at most one match per matching parent node. *) + val childrenO : parentI ::: Type -> parent ::: Type -> children ::: {(Type * Type)} -> pattern parentI parent -> $(map (fn (i, d) => pattern i d) children) -> folder children -> pattern (childrenInternal parentI (map fst children)) (parent * $(map (fn (i, d) => option d) children)) +(* A version of [children] where each child pattern need not be matched *) con treeInternal :: Type -> Type -> Type val tree : parentI ::: Type -> parent ::: Type -> childI ::: Type -> child ::: Type -> pattern parentI parent -> pattern childI child -> pattern (treeInternal parentI childI) (parent * child) +(* A combinator that takes in a pattern for a parent node and another pattern to + * be matched at any depth within the parent's subtree. Unlike [children], + * [tree] finds as many subtree matches per parent node as possible. *) type document val show_document : show document +(* Type of uninterpreted XML documents *) -val fetch : string (* url *) -> transaction document +val fetch : string -> transaction document +(* Retrieve a document by URL. *) + val app : internal ::: Type -> data ::: Type -> pattern internal data -> (data -> transaction {}) -> document -> transaction {} +(* Find all matches of a pattern in a document, running an imperative function + * on the data returned by each match. *) diff -r 05a28a77f6fe -r a4e5d053daed tests/mr.ur --- a/tests/mr.ur Thu Mar 10 18:36:50 2011 -0500 +++ b/tests/mr.ur Sat Mar 19 14:35:11 2011 -0400 @@ -1,12 +1,14 @@ fun main () = + doc <- Feed.fetch "http://marginalrevolution.com/feed"; + Feed.app (Feed.children - (Feed.tagA "item" {1 = "rdf:about"}) - (Feed.tagC "title", Feed.tagC "content:encoded")) - (fn (item, props) => - debug ("URL: " ^ item.1); - debug ("Title: " ^ props.1); - debug ("Content: " ^ props.2)) - "http://feeds.feedburner.com/marginalrevolution/hCQh"; + (Feed.tagA "item" ()) + (Feed.tagC "link", Feed.tagC "title", Feed.tagC "content:encoded")) + (fn ((), (link, title, content)) => + debug ("URL: " ^ link); + debug ("Title: " ^ title); + debug ("Content: " ^ content)) + doc; return See stdout.