diff options
author | Johannes Rudolph <johannes_rudolph@gmx.de> | 2012-05-31 14:05:52 +0200 |
---|---|---|
committer | Johannes Rudolph <johannes_rudolph@gmx.de> | 2012-05-31 14:05:52 +0200 |
commit | 76cb7ff8fc34b3ff723cac87ca544fb6030b31a7 (patch) | |
tree | 351819ec3d0e4be01d611af022fbe6c437c766f2 /src/main/scala | |
parent | fca223087a0fbf59be52b8d2187f576924eaaf25 (diff) | |
download | spray-json-76cb7ff8fc34b3ff723cac87ca544fb6030b31a7.tar.gz spray-json-76cb7ff8fc34b3ff723cac87ca544fb6030b31a7.tar.bz2 spray-json-76cb7ff8fc34b3ff723cac87ca544fb6030b31a7.zip |
initial JsonPath support
Diffstat (limited to 'src/main/scala')
-rw-r--r-- | src/main/scala/cc/spray/json/JsonPathParser.scala | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/src/main/scala/cc/spray/json/JsonPathParser.scala b/src/main/scala/cc/spray/json/JsonPathParser.scala new file mode 100644 index 0000000..b216e28 --- /dev/null +++ b/src/main/scala/cc/spray/json/JsonPathParser.scala @@ -0,0 +1,70 @@ +package cc.spray.json + +import org.parboiled.scala._ +import org.parboiled.errors.{ErrorUtils, ParsingException} + +object JsonPathParser extends Parser { + def JsonPathExpr = rule { Tree ~ EOI } + + def Tree: Rule1[JsonPath.Expr] = rule { Root ~ OptionalSelection } + + def Root: Rule1[JsonPath.Root.type] = rule { "$" ~ push(JsonPath.Root) } + + /* + * To remove the left-recursion I had to factor out Root to here + */ + def OptionalSelection : ReductionRule1[JsonPath.Expr, JsonPath.Expr] = rule { + Projection ~~> JsonPath.Selection ~ OptionalSelection | + EMPTY ~~> identity + } + + def Projection: Rule1[JsonPath.Projection] = rule { + "." ~ DotProjection | + "[" ~ BracketProjection ~"]" + } + + def DotProjection: Rule1[JsonPath.Projection] = rule { + AllElements | ByFieldName + } + def AllElements = rule { "*" ~ push(JsonPath.AllElements) } + def ByFieldName = rule { FieldName ~~> JsonPath.ByField } + + def BracketProjection: Rule1[JsonPath.Projection] = rule { + JsonParser.Digits ~> (d => JsonPath.ByIndex(d.toInt)) | + SingleQuotedString ~~> JsonPath.ByField + } + + def FieldName: Rule1[String] = rule { + oneOrMore(!anyOf(".") ~ ANY) ~> identity + } + + def SingleQuotedString: Rule1[String] = + rule { "'" ~ push(new java.lang.StringBuilder) ~ zeroOrMore(!anyOf("'") ~ ("\\" ~ JsonParser.EscapedChar | JsonParser.NormalChar)) } ~ "'" ~~> (_.toString) + + /** + * The main parsing method. Uses a ReportingParseRunner (which only reports the first error) for simplicity. + */ + def apply(path: String): JsonPath.Expr = apply(path.toCharArray) + + /** + * The main parsing method. Uses a ReportingParseRunner (which only reports the first error) for simplicity. + */ + def apply(path: Array[Char]): JsonPath.Expr = { + val parsingResult = ReportingParseRunner(JsonPathExpr).run(path) + parsingResult.result.getOrElse { + throw new ParsingException("Invalid JSON source:\n" + ErrorUtils.printParseErrors(parsingResult)) + } + } +} + +object JsonPath { + sealed trait Expr + case object Root extends Expr + case class Selection(previous: Expr, projection: Projection) extends Expr + + sealed trait Projection + case object AllElements extends Projection + case class ByField(name: String) extends Projection + case class ByIndex(idx: Int) extends Projection + //case class ByPredicate() +}
\ No newline at end of file |