Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Feb 16 12:07

    nrinaudo on update-sbt-1.6.2

    (compare)

  • Feb 16 12:05

    nrinaudo on master

    Update sbt to 1.6.2 Merge pull request #141 from nr… (compare)

  • Feb 16 12:05
    nrinaudo closed #141
  • Feb 16 11:43
    nrinaudo opened #141
  • Feb 16 11:43

    nrinaudo on update-sbt-1.6.2

    Update sbt to 1.6.2 (compare)

  • Feb 16 11:10

    nrinaudo on update-kantan.sbt-2.8.2

    (compare)

  • Feb 16 11:10

    nrinaudo on master

    Update to kantan.sbt 2.8.2 Merge pull request #140 from nr… (compare)

  • Feb 16 11:10
    nrinaudo closed #140
  • Feb 16 10:59
    nrinaudo opened #140
  • Feb 16 10:59

    nrinaudo on update-kantan.sbt-2.8.2

    Update to kantan.sbt 2.8.2 (compare)

  • Jan 13 17:59
    scala-steward closed #135
  • Jan 13 17:59
    scala-steward commented #135
  • Jan 13 17:59
    scala-steward opened #139
  • Dec 21 2021 05:16
    scala-steward closed #137
  • Dec 21 2021 05:16
    scala-steward commented #137
  • Dec 21 2021 05:16
    scala-steward opened #138
  • Dec 15 2021 11:09
    scala-steward closed #136
  • Dec 15 2021 11:09
    scala-steward commented #136
  • Dec 15 2021 11:09
    scala-steward opened #137
  • Dec 10 2021 19:13
    scala-steward opened #136
Jisoo Park
@guersam
Thanks for making this library! How can I decode an optional field in a case class more tolerantly, like allowing an attribute having an empty string to be None?
Currently I'm adding a condition like [not(.='')] to the xpath query and it just works, but I wonder if there's more idiomatic way.
Nicolas Rinaudo
@nrinaudo
That seems pretty good to me - your xpath describes the shape of your data, and you use decoders to interpret it
You could also write a custon Decoder[String] that turns Some(“”) into Nonr
None
Jisoo Park
@guersam
Thanks for the quick response, I'll stick with this approach. Before that, I was trying to write a custom NodeDecoder[Option[A]] with Decoder.optionalDecoder and Decoder#handleErrorWith but failed to prove that there is an implicit IsError[DecodeError]. Do you have any clue?
Nicolas Rinaudo
@nrinaudo
Not without your code, no. Or did you mean a clue on how to write the decoder?
Nicolas Rinaudo
@nrinaudo
If you meant with the decoder, I think something like this should work:
NodeDecoder.optionNodeDecoder[String].filter(_ != "")
I would prefer to write:
implicit val lenientStringDecoder: NodeDecoder[Option[String]] = NodeDecoder[Option[String]].map(_.filter(_ != ""))
but that's not possible, Scala makes it unpleasant to "refine" an implicit value - given an implicit T, replace it with a new one adapted from it
(none of this code has been tried in the REPL, so if it doesn't compile, it's likely not your fault)
Jisoo Park
@guersam

I lost my first failed implementation and it's my second attempt without optionalDecoder:

  implicit def tolerantOptionDecoder[A](implicit ev: NodeDecoder[A]): NodeDecoder[Option[A]] =
    NodeDecoder.from {
      case Some(n) if n.getTextContent == "" => Right(None)
      case n @ Some(_) => ev.decode(n).map(Some(_))
      case None => Right(None)
    }

I'm not sure if Node#getTextContent makes sense here

Nicolas Rinaudo
@nrinaudo
Mmm... I might have misunderstood your intent
do you want a NodeDecoder[Option[String]] that's treats the empty string as a None, or do you want something that treats the empty string as the absence of node?
if the later, I'd need to play with it a bit, but I think a better solution would be to contramap on your decoder - turn Some(EmptyNode) into Node before the decoder is even called
Jisoo Park
@guersam
The former. I think contramap would work in this case too
Nicolas Rinaudo
@nrinaudo
if You want a NodeDecoder[Option[String]], then what I pasted before should work:
implicit val decoder: NodeDecoder[Option[String]] = NodeDecoder.optionNodeDecoder[String].filter(_ != "")
Mmm.... apparently it does not. Let me play with this for a bit
Nicolas Rinaudo
@nrinaudo
Right, this works:
def lenient[A: NodeDecoder](nonEmpty: A => Boolean) = NodeDecoder[Option[A]].map(_.filter(nonEmpty))

implicit val lenientString: NodeDecoder[Option[String]] = lenient(_ != "")

"<root id=''/>".evalXPath[Option[String]](xp"/root/@id")
// res1: kantan.xpath.XPathResult[Option[String]] = Right(None)

"<root id='foo'/>".evalXPath[Option[String]](xp"/root/@id")
// res2: kantan.xpath.XPathResult[Option[String]] = Right(Some(foo))

 "<root/>".evalXPath[Option[String]](xp"/root/@id")
// res3: kantan.xpath.XPathResult[Option[String]] = Right(None)
There. Was that what you had in mind?
Owen Healy
@ellbur
so, this is probably a silly question, but if I want to run multiple queries on the same document, is there a way to parse it once and run .evalXPath repeatedly on the result?
Nicolas Rinaudo
@nrinaudo
Sure, you can take any node org.w3c.dom.Node and execute all the xpath evaluation methods on it
this is achieved through the XmlSource type class, which provides the instance you need: https://github.com/nrinaudo/kantan.xpath/blob/master/core/src/main/scala/kantan/xpath/XmlSource.scala#L101
if you need to store your documents in another type, no worries, just declare an implicit XmlSource[YourDocumentType]
Owen Healy
@ellbur
Perfect, thank you. I had missed that that instance existed.