Skip to content

Instantly share code, notes, and snippets.

@benkolera
Created April 15, 2014 23:34
Show Gist options
  • Save benkolera/10789041 to your computer and use it in GitHub Desktop.
Save benkolera/10789041 to your computer and use it in GitHub Desktop.
import scalaz._
import syntax.std.option._
import syntax.monad._
import syntax.show._
import xml._
import cursor._
import Xml._
object DecoderTest {
//
// -- Some types + decoders for attrs and grabbing text from elements --------
case class DecodeError(
cursorHistory: History ,
decodeDesc: String ,
err: String
)
type DecodeResult[+A] = DecodeError \/ A
type DecoderT[M[+_],+A] = Kleisli[M,Content,A]
type Decoder[+A] = DecoderT[DecodeResult,A]
def decoder[A]( run:Content => DecodeResult[A] ):Decoder[A] = {
Kleisli[DecodeResult,Content,A]( run )
}
def shiftedContent(
s:Shift , desc:String
)(
c:Content
): DecodeResult[(History,Content)] = {
val hc = s.run( c )
hc.cursor.map( hc.history -> ~_ ).toRightDisjunction(
DecodeError( hc.history , desc, "Failed cursor" )
)
}
def attributeDecoder( attrName:String )( s:Shift ) = decoder[String] { c =>
val desc = s"Find attr $attrName"
shiftedContent( s , desc )(c).flatMap{ case (h,c) =>
c.elem.flatMap(
_.attribs.find( _.key.name == attrName.toList )
).fold[DecodeResult[String]](
-\/(DecodeError(h,desc,"Couldn't find attribute"))
)( attr =>
\/-(attr.value.mkString)
)
}
}
def textDecoder( s:Shift ) = decoder[String] { c =>
val desc = s"Find text element"
shiftedContent( s , desc )(c).flatMap{ case (h,c) =>
c.elem.fold[DecodeResult[String]](
-\/(DecodeError(h,desc,"Cursor was not at an element"))
)( e =>
\/-(e.strContent.mkString)
)
}
}
// -- Some helper predicates -------------------------------------------------
def nameCPred( name:String ) = Predicate.predicate[Cursor](
c => c.current.elem.map( _.name.name == name.toList ).getOrElse(false) ,
Some( s"Element named: $name".toList )
)
val findRecName: String => Shift = nameCPred _ andThen findRec
val findChildName: String => Shift = nameCPred _ andThen findChild
// -- And now lets run it ----------------------------------------------------
val xmlStr = """<envelope>
<header>
<headerstuff>Stuff<headerstuff>
</header>
<body>
<field1><nestedfield>foo</nestedfield></field1>
<field2 attra="attribute a">bar</field2>
</body>
</envelope>"""
def main( args:Array[String] ):Unit = {
val p = xmlStr.parseXml
val attra = attributeDecoder( "attra" )( findRecName( "field2" ) )
var nField = textDecoder(
findRecName("field1") >=> findChildName("nestedfield")
)
val r = ( attra |@| nField ){ (a,b) => s"Attrib($a) Field:($b)" }.run( p.head )
println( r )
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment