module Cul module Hydra module Datastreams class StructMetadata < ::ActiveFedora::Datastream include ::ActiveFedora::Datastreams::NokogiriDatastreams def self.default_attributes super.merge(:controlGroup => 'M', :mimeType => 'text/xml') end def self.xml_template Nokogiri::XML::Document.parse("<mets:structMap xmlns:mets=\"http://www.loc.gov/METS/\">") end def self.div_template(prefix="mets") prefix.nil? ? '<div/>' : "<#{prefix}:div/>" end def initialize(digital_object=nil, dsid=nil, options={}) super end # Indicates that this datastream has metadata content. # @return true def metadata? true end def autocreate? changed_attributes.has_key? :profile end def label=(value) struct_map["LABEL"] = value ng_xml_will_change! end def label struct_map["LABEL"] end def type=(value) struct_map["TYPE"] = value ng_xml_will_change! end def type struct_map["TYPE"] end def prefix prefix = nil ng_xml.namespaces.each do |p, href| prefix = p.sub(/xmlns:/,'') if href == "http://www.loc.gov/METS/" end prefix end def struct_map prefix = self.prefix path = prefix.nil? ? 'xmlns:structMap' : "#{prefix}:structMap" ng_xml.xpath(path, ng_xml.namespaces).first end def create_div_node(parent=nil, atts={}) if parent.nil? parent = struct_map end divNode = parent.add_child(StructMetadata.div_template(parent.namespace.prefix)).first [:label, :order, :contentids]. each do |key| divNode[key.to_s.upcase] = atts[key].to_s if atts.has_key? key end ng_xml_will_change! if (divNode.document == ng_xml.document) divNode end def divs_with_attribute(descend=true, name=nil, value=nil) prefix = self.prefix || 'xmlns' xpath = descend ? "//#{prefix}:div" : "/#{prefix}:structMap/#{prefix}:div" if !name.nil? xpath << "[@#{name}" if !value.nil? xpath << "='#{value}'" end xpath << ']' end ng_xml.xpath(xpath, ng_xml.namespaces) end def first_ordered_content_div divs_with_contentids_attr = self.divs_with_attribute(true, 'CONTENTIDS') sorted_divs_with_contentids_attr = divs_with_contentids_attr.sort_by{ |node| node.attr("ORDER").to_i } return sorted_divs_with_contentids_attr.first end # a convenience method for setting attributes and creating divs (if necessary) for R/V structure # returns the mets:structMap node def recto_verso! self.type= 'physical' unless self.type == 'physical' self.label= 'Sides' unless self.label == 'Sides' create_div_node struct_map, {:order=>'1'} unless divs_with_attribute(false,'ORDER','1').first create_div_node struct_map, {:order=>'2'} unless divs_with_attribute(false,'ORDER','2').first if (div = divs_with_attribute(false,'ORDER','1').first) div['LABEL'] = 'Recto' unless div['LABEL'] == 'Recto' end if (div = divs_with_attribute(false,'ORDER','2').first) div['LABEL'] = 'Verso' unless div['LABEL'] == 'Verso' end struct_map end def recto divs_with_attribute(false, 'LABEL', 'Recto').first end def verso divs_with_attribute(false, 'LABEL', 'Verso').first end def to_solr(doc={}) doc[:structured_bsi] = (has_content? ? 'true' : 'false') doc end def proxies divs = divs_with_attribute(true) graph_context_uri = RDF::URI("info:fedora/#{self.pid}") file_system = self.type.eql?(RDF::NFO[:"#Filesystem"].to_s) divs.collect do |div| proxy_uri_chain = proxy_uri_chain_for(div) proxy_resource_uri = proxy_uri_chain.pop if div['CONTENTIDS'] subclass = file_system ? NFO::FileDataObject : SC::Canvas proxy = subclass.new(proxy_resource_uri, graph_context_uri) proxy.proxyFor = RDF::URI(div['CONTENTIDS']) else subclass = file_system ? NFO::Folder : SC::Sequence proxy = subclass.new(proxy_resource_uri, graph_context_uri) end if div.parent and div.parent.name == 'div' proxy.belongsToContainer = proxy_uri_for(div.parent) end proxy.isPartOf = proxy_uri_chain unless proxy_uri_chain.empty? proxy.index = div['ORDER'] proxy.label = div['LABEL'] proxy end end private def ancestors(node) current = node labels = [] while (current.name == 'div') labels.unshift URI.escape(current['LABEL']) current = current.parent end labels end def proxy_uri_chain_for(node) uris = [] ancestors(node).inject(RDF::URI("info:fedora/#{self.pid}/#{self.dsid}")) {|m,a| (uris << m/a).last} uris end def proxy_uri_for(node) # uri = segments.inject(base_uri) {|m,a| m/a} ancestors(node).inject(RDF::URI("info:fedora/#{self.pid}/#{self.dsid}")) {|m,a| m/a} end end end end end