Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

withRemoveNamespaces not work for element attributes if a namespace is defined #19

Open
geny200 opened this issue May 10, 2024 · 1 comment

Comments

@geny200
Copy link
Contributor

geny200 commented May 10, 2024

Hi, addition of a new flag withRemoveNamespaces ( issue #3 , pr #5 ) is a really useful thing, but there is one bug, this config does not work with attributes if namespace is set. Here is an example with a comparison of this flag for an "element" and for "attribute". (it works correctly for "element", it doesn't work for "attribute").

import phobos.Namespace
import phobos.configured.ElementCodecConfig
import phobos.decoding.XmlDecoder
import phobos.derivation.semiauto.{deriveXmlDecoderConfigured, deriveXmlEncoderConfigured}
import phobos.encoding.XmlEncoder
import phobos.syntax.attr

object MyNamespace {
  type ns = MyNamespace.type
  implicit val ns: Namespace[ns] = Namespace.mkInstance[ns]("http://example.com", Some("example"))
}

case class BarAttr(@attr foo: String)

object BarAttr {
  val configEnc: ElementCodecConfig = ElementCodecConfig.default.withAttributesDefaultNamespace(MyNamespace)
  val configDec: ElementCodecConfig = ElementCodecConfig.default.withRemoveNamespaces

  implicit val barXmlEncoder: XmlEncoder[BarAttr] =
    deriveXmlEncoderConfigured[BarAttr]("BarAttr", configEnc)
  implicit val barXmlDecoder: XmlDecoder[BarAttr] =
    deriveXmlDecoderConfigured[BarAttr]("BarAttr", configDec)
}

case class BarElem(foo: String)

object BarElem {
  val configEnc: ElementCodecConfig = ElementCodecConfig.default.withElementsDefaultNamespace(MyNamespace)
  val configDec: ElementCodecConfig = ElementCodecConfig.default.withRemoveNamespaces

  implicit val barXmlEncoder: XmlEncoder[BarElem] =
    deriveXmlEncoderConfigured[BarElem]("BarElem", configEnc)
  implicit val barXmlDecoder: XmlDecoder[BarElem] =
    deriveXmlDecoderConfigured[BarElem]("BarElem", configDec)
}

object App {
  def main(args: Array[String]): Unit = {
    println(XmlEncoder[BarAttr].encode(BarAttr("qwerty")))
    // <?xml version='1.0' encoding='UTF-8'?><BarAttr xmlns:ans1="http://example.com" ans1:foo="qwerty"/>

    println(XmlEncoder[BarElem].encode(BarElem("qwerty")))
    // <?xml version='1.0' encoding='UTF-8'?><BarElem><ans1:foo xmlns:ans1="http://example.com">qwerty</ans1:foo></BarElem>

    val xmlAttr =
      """<?xml version='1.0' encoding='UTF-8'?><BarAttr xmlns:ans1="http://example.com" ans1:foo="qwerty"/>"""
    println(XmlDecoder[BarAttr].decode(xmlAttr))
    // {{{
    // phobos.decoding.DecodingError: Error while decoding XML: Missing 'foo' attribute
    //	In element 'BarAttr'
    // }}}

    val xmlElem =
      """<?xml version='1.0' encoding='UTF-8'?><BarElem><ans1:foo xmlns:ans1="http://example.com">qwerty</ans1:foo></BarElem>"""
    println(XmlDecoder[BarElem].decode(xmlElem))
    // Ok

    // Check law for element
    val y: BarElem = BarElem("qwerty")
    assert(
      XmlEncoder[BarElem]
        .encode(y)
        .toOption
        .flatMap(XmlDecoder[BarElem].decode(_).toOption)
        .contains(y),
    ) // Ok

    // Check law for attribute
    val x: BarAttr = BarAttr("qwerty")
    assert(
      XmlEncoder[BarAttr]
        .encode(x)
        .toOption
        .flatMap(XmlDecoder[BarAttr].decode(_).toOption)
        .contains(x),
    ) // assertion failed
  }
}
@valentiay
Copy link
Owner

Hi!
Thank you for reporting this issue.
This is a tricky one. I'll need some more time to investigate why does it work that way. I'm surprised, that it does not break the law for elements

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants