lutaml / lutaml-model

LutaML Model is the Ruby data modeler part of the LutaML data modeling suite. It supports creating serialization object models (XML, YAML, JSON, TOML) and mappings to and from them.
Other
2 stars 2 forks source link

Mechanism for user to "swap out" or "passthrough" an attribute of a class in the lutaml-model class tree #142

Open ronaldtse opened 3 weeks ago

ronaldtse commented 3 weeks ago

In the oasis-etm gem, the <entry> element is meant to accept anything (in XML) that user wishes.

Clearly, this content won't be defined in the oasis-etm gem but by the user.

There are 2 ways the user wants to handle this:

In the first case, we need a way for the user to say that "give me this string as it is without parsing it as XML".

In the second case, we need a way for users of this gem to "swap out" the Entry class with their own "SpecialEntry" so they can process the content of Entry.

Both map_all and raw: true do not seem to be proper solutions to this use case.

Let's propose a syntax to support both cases..

Illustration from original issue

In the XML file, it contains this content:

<row>
  <entry>b1</entry>
  <entry>b2</entry>
  <entry>b3</entry>
  <entry>b4</entry>
  <entry morerows='1' valign='middle'><para>  <!-- Pernicous Mixed Content -->
  Vertical Span</para></entry>
</row>

The element <entry ...><para>...</para></entry> fails because the <para>...</para> content is not defined in lutaml-model, and therefore omitted from the re-generated content.

This is a case where the content of an element is not defined, and we need to implement some pass-through.

Clearly, map_all won't work here because we still need to retain the attributes.

So I thought of using raw: true:

module Oasis
  module Etm
    class Entry < Lutaml::Model::Serializable
      attribute :colname, :string
      attribute :content, :string, raw: true
      # ...

      xml do
        root "entry"

        # Attribute mappings
        map_attribute "colname", to: :colname
        # ...

        # Content mapping
        map_content to: :content
      end
    end
  end
end

But it still doesn't work.

Originally posted by @ronaldtse in https://github.com/lutaml/oasis-etm/issues/1#issuecomment-2451449564

HassanAkbar commented 3 weeks ago

@ronaldtse By looking at the issue I think

@ronaldtse What do you think about this?

ronaldtse commented 3 weeks ago

We can allow map_attribute with map_all, With this we can map all the content and map attributes to different values or we can also give a map_all_attributes method to map all the attributes to a hash or string.

Then we should have "map_all", "map_all_content" and "map_all_attributes"?

We can allow something like Oasis::Etm::Entry.add_attribute or Oasis::Etm::Entry.add_element and also Oasis::Etm::Entry.remove_element, syntax can also be like Oasis::Etm::Entry.add("entry", type: :element)

Let me think...

HassanAkbar commented 3 weeks ago

Then we should have "map_all", "map_all_content" and "map_all_attributes"?

@ronaldtse Currently map_all is doing the same thing that we will be expecting from map_all_content. I think we can rename map_all to map_all_content and add a new method for map_all_attributes.

What do you suggest?

ronaldtse commented 1 week ago

we can rename map_all to map_all_content and add a new method for map_all_attributes

Agree. Let's do that.

However, we will still need a way to override a particular attribute/class in a lutaml-model class tree.

HassanAkbar commented 1 week ago

Agree. Let's do that.

Got it, I'm on it.

However, we will still need a way to override a particular attribute/class in a lutaml-model class tree.

For attributes, I'm thinking of keeping a hash because attributes will always be strings. So we can update the value of a single attribute for the element by changing the hash value.

For overriding the class I think we can provide methods to update attributes so we can change their type so it can be handled with different class. i.e Person.update_attribute(:name, { type: MyCustomStringClass }). Something like this.

@ronaldtse What do you think?