Skip to content

Commit

Permalink
Merge pull request #310 from jet-black/master
Browse files Browse the repository at this point in the history
Ability to ignore unknown elements in response
  • Loading branch information
eed3si9n committed Apr 21, 2015
2 parents d502f33 + 30b7ce8 commit 539ea27
Show file tree
Hide file tree
Showing 14 changed files with 570 additions and 19 deletions.
59 changes: 58 additions & 1 deletion cli/src/main/resources/scalaxb.scala.template
Expand Up @@ -619,9 +619,66 @@ trait AnyElemNameParser extends scala.util.parsing.combinator.Parsers {
import scala.annotation.tailrec
type Elem = ElemName

implicit class ReaderExt(reader: scala.util.parsing.input.Reader[ElemName]) {

def erased(from: Int, to: Int): scala.util.parsing.input.Reader[ElemName] = {
reader match {
case r: ElemNameSeqReader =>
new ElemNameSeqReader(r.seq.take(from) ++ r.seq.drop(to))
case other =>
throw new UnsupportedOperationException("Incompatible reader")
}
}

}

implicit class ParserExt[+T, P <% Parser[T]](current: P) {

private def parseIterable[P, T](source: Input, in: Input, p: Parser[P], res: ParseResult[P]): ParseResult[P] = {
res match {
case s@Success(v: Option[_], n) if v.isEmpty =>
if (!n.atEnd) parseIterable(source, in.rest, p, p(in.rest)) else s.copy(next = source)
case s@Success(v: Iterable[_], n) if v.isEmpty =>
if (!n.atEnd) parseIterable(source, in.rest, p, p(in.rest)) else s.copy(next = source)
case s@Success(v, n) =>
s.copy(next = n.erased(in.pos.column - 1, n.pos.column - 1))
case other =>
other
}
}

private def lookupSuccess[P](p: Parser[P], input: Input): ParseResult[P] = p(input) match {
case s@Success(v, next) =>
parseIterable(input, input, p, s)
case n@NoSuccess(b, next) =>
if (next.atEnd) n
else lookupSuccess(p, input.rest)
}

def ~|~[U](nextParser: => Parser[U]): Parser[~|~[T, U]] =
Parser {
in =>
lookupSuccess(current, in) match {
case s@Success(currentResult, afterFirstInput) =>
lookupSuccess(nextParser, afterFirstInput) match {
case qs@Success(nextResult, afterSecondInput) =>
Success(new ~|~(currentResult, nextResult), afterSecondInput)
case n: NoSuccess => n
}
case n: NoSuccess => n
}
}
}

case class ~|~[+A, +B](a : A, b : B) {
override def toString() = s"$a ~|~ $b"
}

// we need this so treat ElemName as NodeSeq for fromXML etc.
implicit def toNodeSeq(elem: Elem): scala.xml.NodeSeq = elem.node

def optPhrase[U](p: Parser[U]): Parser[U] = phrase(p ~|~ safeRep(any(_ => true)) ^^ {case p1 ~|~ p2 => p1})

def any(f: ElemName => Boolean): Parser[ElemName] =
accept("any", { case x: ElemName if x.name != "" && f(x) => x })

Expand Down Expand Up @@ -719,7 +776,7 @@ trait ElemNameParser[A] extends AnyElemNameParser with XMLFormat[A] with CanWrit
else in collect { case x: scala.xml.Elem => ElemName(x) }
}

class ElemNameSeqReader(seq: Seq[ElemName],
class ElemNameSeqReader(val seq: Seq[ElemName],
override val offset: Int) extends scala.util.parsing.input.Reader[ElemName] {
import scala.util.parsing.input._

Expand Down
4 changes: 3 additions & 1 deletion cli/src/main/scala/scalaxb/compiler/Main.scala
Expand Up @@ -119,7 +119,9 @@ object Arguments {
opt[Boolean]("use-varargs") text("use var arguments") action { (x, c) =>
c.copy(useVarArg = x) }
opt[Unit]("generate-lens") text("Generate lenses") action { (_, c) =>
c.copy(generateLens = true) }
c.copy(flags = c.flags + ("generateLens" -> true)) }
opt[Unit]("ignore-unknown") text("Ignore Unknown Elements") action { (_, c) =>
c.copy(flags = c.flags + ("ignoreUnknown" -> true)) }
help("help") text("display this message")
version("version") text("display version info")
arg[File]("<schema_file>...") unbounded() text("input schema to be converted") action { (x, c) =>
Expand Down
8 changes: 7 additions & 1 deletion cli/src/main/scala/scalaxb/compiler/Module.scala
Expand Up @@ -52,7 +52,13 @@ case class Config(packageNames: Map[Option[String], Option[String]] = Map(None -
async: Boolean = true,
dispatchVersion: String = scalaxb.BuildInfo.defaultDispatchVersion,
useVarArg : Boolean = true,
generateLens: Boolean = false)
flags: Map[String, Boolean] = Map()) {

def generateLens: Boolean = flags.getOrElse("generateLens", false)

def ignoreUnknown: Boolean = flags.getOrElse("ignoreUnknown", false)

}

object Snippet {
def apply(definition: Node): Snippet = Snippet(definition, Nil, Nil, Nil)
Expand Down
2 changes: 1 addition & 1 deletion cli/src/main/scala/scalaxb/compiler/wsdl11/GenSource.scala
Expand Up @@ -288,7 +288,7 @@ trait {interfaceTypeName} {{
def splitParamToParts(paramType: XParamType, paramBinding: Option[XStartWithExtensionsTypable]): (Seq[XPartType], Seq[XPartType]) = {
val headers = headerBindings(paramBinding)
val headerPartNames = (headers map { _.part }).toSet
val parts = paramMessage(paramType).part
val parts = paramMessage(paramType).part.map(x => x.copy(name = x.name.map(camelCase)))
val (headerParts, bodyParts) = parts partition { p => headerPartNames(p.name.getOrElse("")) }
(headerParts, bodyParts)
}
Expand Down
2 changes: 1 addition & 1 deletion cli/src/main/scala/scalaxb/compiler/xsd/GenProtocol.scala
Expand Up @@ -64,7 +64,7 @@ abstract class GenProtocol(val context: XsdContext) extends ContextProcessor {
case Some(ns) if scopeSchemas.toList forall {_.elementQualifiedDefault} => List(None -> ns)
case _ => Nil }) :::
(scopeSchemas.toList flatMap {makeScope _}) :::
(serviceTargetNamespaces.toList.zipWithIndex map { case (ns, idx) => Some("tns" + idx.toString) -> ns }) :::
(serviceTargetNamespaces.toList.zipWithIndex map { case (ns, idx) => Some("tns") -> ns }) :::
List((Some(XSI_PREFIX) -> XSI_URL), (Some(XS_PREFIX) -> XS_URL))).distinct, 0)
val packageString = config.protocolPackageName map { "package " + _ + newline } getOrElse{""}
val importFutureString = if (config.async)
Expand Down
4 changes: 2 additions & 2 deletions cli/src/main/scala/scalaxb/compiler/xsd/GenSource.scala
Expand Up @@ -396,8 +396,8 @@ abstract class GenSource(val schema: SchemaDecl,
else ""
}{ if (effectiveMixed) "override def isMixed: Boolean = true" + newline + newline + indent(2)
else "" }def parser(node: scala.xml.Node, stack: List[scalaxb.ElemName]): Parser[{fqn}] =
phrase({ parserList.mkString(" ~ " + newline + indent(3)) } ^^
{{ case { parserVariableList.mkString(" ~ ") } =>
{phrase}({ parserList.mkString(" " + follow + " " + newline + indent(3)) } ^^
{{ case { parserVariableList.mkString(s" $follow ") } =>
{fqn}({argsString}) }})

{makeWritesAttribute}{makeWritesChildNodes} }}</source>
Expand Down
17 changes: 10 additions & 7 deletions cli/src/main/scala/scalaxb/compiler/xsd/Parsers.scala
Expand Up @@ -29,10 +29,13 @@ import scala.collection.immutable

trait Parsers extends Args with Params {
private val logger = Log.forName("xsd.Parsers")

lazy val (follow, phrase) = if (config.ignoreUnknown) ("~|~", "optPhrase") else ("~", "phrase")

// called by makeCaseClassWithType and buildSeqParser
def buildParser(particle: Particle, mixed: Boolean, wrapInDataRecord: Boolean, ignoreSubGroup: Boolean): String =
buildParser(particle, buildOccurrence(particle), mixed, wrapInDataRecord, ignoreSubGroup)

def buildParser(particle: Particle, occurrence: Occurrence,
mixed: Boolean, wrapInDataRecord: Boolean, ignoreSubGroup: Boolean): String = particle match {
case elem: ElemDecl => buildElemParser(elem, occurrence, mixed, wrapInDataRecord, ignoreSubGroup)
Expand Down Expand Up @@ -60,9 +63,9 @@ trait Parsers extends Args with Params {
}).mkString("List(", ", ", ")")
})

buildParserString(if (mixed) "((" + parser + " ^^ (" + converter + ")) ~ " + newline +
buildParserString(if (mixed) "((" + parser + " ^^ (" + converter + ")) " + follow + newline +
indent(3) + buildTextParser + ") ^^ " + newline +
indent(3) + "{ case p1 ~ p2 => Seq.concat(Seq(p1), p2.toList) }"
indent(3) + s"{ case p1 $follow p2 => Seq.concat(Seq(p1), p2.toList) }"
else if (wrapInDataRecord) "(" + parser + " ^^ (" + converter + "))"
else parser,
occurrence)
Expand Down Expand Up @@ -127,7 +130,7 @@ trait Parsers extends Args with Params {

"{ case " +
(if (seq.particles.size == 0) "_"
else parserVariableList.mkString(" ~ ")) +
else parserVariableList.mkString(s" $follow ")) +
(if (mixed) " => Seq.concat(" + argsString + ")"
else {
val apply0 = fqn + "(" + argsString + ")"
Expand All @@ -139,7 +142,7 @@ trait Parsers extends Args with Params {
" }"
}

val base = parserList.mkString("(", " ~ " + newline + indent(3), ")") + " ^^ " + newline +
val base = parserList.mkString("(", " " + follow + " " + newline + indent(3), ")") + " ^^ " + newline +
indent(4) + buildSeqConverter(seq, mixed, wrapInDataRecord)
val retval = buildParserString(base, occurrence)
logger.debug("buildSeqParser: " + seq + newline + retval)
Expand All @@ -153,7 +156,7 @@ trait Parsers extends Args with Params {
"{ case p => foo()}"
}

val base = parserList.mkString("(", " ~ " + newline + indent(3), ")") + " ^^ " + newline +
val base = parserList.mkString("(", " " + follow + " " + newline + indent(3), ")") + " ^^ " + newline +
indent(3) + buildAllConverter(all)
buildParserString(base, occurrence)
}
Expand All @@ -178,7 +181,7 @@ trait Parsers extends Args with Params {
val singleOccurrence = occurrence.copy(minOccurs = 1, maxOccurs = 1)

// expand substitution groups into elements
var options = choice.particles flatMap { _ match {
val options = choice.particles flatMap { _ match {
case any: AnyDecl => Nil
case compositor: HasParticle if isEmptyCompositor(compositor) => Nil
case elem: ElemDecl =>
Expand Down

0 comments on commit 539ea27

Please sign in to comment.