require 'xml/mapping_extensions' module Datacite module Mapping # Controlled vocabulary of description types. class DescriptionType < TypesafeEnum::Base # @!parse ABSTRACT = Abstract new :ABSTRACT, 'Abstract' # @!parse METHODS = Methods new :METHODS, 'Methods' # @!parse SERIES_INFORMATION = SeriesInformation new :SERIES_INFORMATION, 'SeriesInformation' # @!parse TABLE_OF_CONTENTS = TableOfContents new :TABLE_OF_CONTENTS, 'TableOfContents' # @!parse OTHER = Other new :OTHER, 'Other' end # XML mapping class preserving `
` tags in description values class BreakPreservingValueNode < XML::Mapping::SingleAttributeNode # Collapses a sequence of text nodes and `
` tags into a single string value. # Implements `SingleAttributeNode#xml_to_obj`. # @param obj [Description] the object being created # @param xml [REXML::Element] the XML being read def xml_to_obj(obj, xml) value_str = xml.children.map { |c| c.respond_to?(:value) ? c.value : c.to_s }.join obj.value = value_str.strip end # Converts a string value to a sequence of text nodes and `
` tags. # Implements `SingleAttributeNode#obj_to_xml`. # @param obj [Description] the object being serialized # @param xml [REXML::Element] the XML being written def obj_to_xml(obj, xml) value_str = obj.value || '' values = value_str.split(%r{|
[^<]*
}) values.each_with_index do |v, i| xml.add_text(v) xml.add_element('br') unless i + 1 >= values.size end end end XML::Mapping.add_node_class BreakPreservingValueNode # A additional information that does not fit in the other more specific {Resource} # attributes. # # Note: In accordance with the DataCite spec, description text can be separated by # HTML `
` tags. The {Description} class will preserve these, but at the expense # of converting escaped `
` in text values to actual `
` tags. For example, # when reading the following tag: # # # Line 1
Line 2 containing escaped <br/> tag
Line 3 #
# # the value will be returned as the string # # "Line 1
Line 2 containing escaped
tag
Line 3" # # in which it is impossible to distinguish the escaped an un-escaped `
`s. The # value would thus be written back to XML as: # # # Line 1
Line 2 containing escaped
tag
Line 3 #
# # Other escaped HTML or XML tags will still be escaped when written back, and other # un-escaped HTML and XML tags are of course not allowed. class Description include XML::Mapping # Initializes a new {Description} # @param language [String] an IETF BCP 47, ISO 639-1 language code identifying the language. # It's unclear from the spec whether language is required; to play it safe, if it's missing, we default to 'en'. # @param type [DescriptionType] the description type. # @param value [String] the description itself. See {Description} for notes on special # handling of `
` tags. def initialize(language: 'en', type:, value:) self.language = language self.type = type self.value = value end def language @language || 'en' end def language=(value) @language = value.strip if value end # @!attribute [rw] language # @return [String] an IETF BCP 47, ISO 639-1 language code identifying the language. # It's unclear from the spec whether language is required; to play it safe, if it's missing, we default to 'en'. text_node :language, '@xml:lang', default_value: nil # @!attribute [rw] type # @return [DescriptionType] the description type. typesafe_enum_node :type, '@descriptionType', class: DescriptionType # @!attribute [rw] value # @return [String] the description itself. See {Description} for notes on special # handling of `
` tags. break_preserving_value_node :value, 'node()' end end end