Search code examples
phpxmljms-serializer

JMS Serializer to read xml:lang attribute


This is related to xml:lang parse in PHP.

We use JMS serializer to create XML requests to and parse XML responses from Sirena-Travel (airticket provider). A whole system of annotated DTOs is built around this serializer, and we're unlikely to change this.

There is a reponse XML we'd like to deserialize (the same as in the above question):

<?xml version="1.0" encoding="UTF-8"?>
  <answer>
    <describe data="aircompany">
      <data>
        <code xml:lang="ru">FW</code>
        <code xml:lang="en">FW</code>
      </data>
      <data>
        <code xml:lang="ru">UT</code>
        <code xml:lang="en">ЮТ</code>
      </data>
    </describe>
  </answer>

The question is: How do I specify a property corresponding to xml:lang attribute?

This is how classes describing the innermost elements look like:

class DescribeData
{
    /**
     * Codes in various languages.
     *
     * @Type("array<DescribeLangElement>")
     * @XmlList(inline = true, entry = "code")
     */
    private $codes = [];

    public function getCode($lang)
    {
        foreach ($this->codes as $code) {
            if ($code->getLang() === $lang) {
                return $code;
            }
        }
        return null;
    }
}

class DescribeLangElement
{
    /**
     * Element's language code.
     *
     * Either "en" or "ru".
     *
     * @Type("string")
     * @XmlAttribute
     */
    private $lang;

    /**
     * @Type("string")
     * @XmlValue
     */
    private $value;
}

Obviously, the serializer does not recognize xml:lang attribute as $lang property. I tried a couple of approaches:

  • Add @SerializedName("xml:lang") to $lang property.
  • Add namespace annotation:

     @XmlNamespace(uri = "http://example.com/", prefix = "xml")
    

    either to the parent node or to the root node, while modifying @XmlAttribute annotation on $lang property to look like

     @XmlAttribute(namespace = "http://example.com/")
    

Needless to say, no success with either or both of them.

I also have in mind alternate solutions like:

  • Preprocess the XML to convert xml:lang attribute to lang.
  • Write a custom deserialization handler to deal with DescribeLangElement class.

But those seem like an overkill to me.

Is there a straight-forward way to specify a property for xml:lang attribute with JMS serializer annotations?


Solution

  • Namespace constraint: Reserved Prefixes and Namespace Names

    The prefix xml is by definition bound to the namespace name http://www.w3.org/XML/1998/namespace. It may, but need not, be declared, and must not be undeclared or bound to any other namespace name. Other prefixes must not be bound to this namespace name, and it must not be declared as the default namespace.

    From: http://www.w3.org/TR/xml-names11/#xmlReserved

    Therefore the namespace is not http://example.com/ but http://www.w3.org/XML/1998/namespace.