ruby-avm-library/lib/avm/xmp.rb

155 lines
4.0 KiB
Ruby
Raw Normal View History

2011-03-10 22:45:21 +00:00
require 'nokogiri'
require 'avm/node'
2011-03-10 22:45:21 +00:00
module AVM
2011-03-23 18:10:02 +00:00
# An XMP document wrapper, providing namespace handling and document reference assistance.
2011-03-10 22:45:21 +00:00
class XMP
2011-03-14 16:35:29 +00:00
PREFIXES = {
'dc' => 'Dublin Core',
'Iptc4xmpCore' => 'IPTC',
2011-03-15 14:55:09 +00:00
'photoshop' => 'Photoshop',
'avm' => 'AVM'
2011-03-14 16:35:29 +00:00
}
REQUIRED_NAMESPACES = {
:x => "adobe:ns:meta/",
:rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
:dc => "http://purl.org/dc/elements/1.1/",
:photoshop => "http://ns.adobe.com/photoshop/1.0/",
:avm => "http://www.communicatingastronomy.org/avm/1.0/",
:Iptc4xmpCore => "http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/"
}
2011-03-10 22:45:21 +00:00
attr_reader :doc
2011-03-11 18:27:17 +00:00
def initialize(doc = nil)
@doc = doc || empty_xml_doc
ensure_namespaces!
ensure_descriptions_findable!
2011-03-10 22:45:21 +00:00
end
2011-03-11 18:27:17 +00:00
def get_refs
2011-03-14 16:35:29 +00:00
yield Hash[[ :dublin_core, :iptc, :photoshop, :avm ].collect { |key| [ key, send(key) ] }]
2011-03-10 22:45:21 +00:00
end
2011-03-11 18:27:17 +00:00
def self.from_string(string)
new(Nokogiri::XML(string))
end
def ensure_xmlns(string)
string.gsub(%r{([</@])(\w+):}) { |all, matches| $1 + (prefix_map[$2] || $2) + ':' }
end
alias :% :ensure_xmlns
def ensure_xpath(path)
[ ensure_xmlns(path), namespaces ]
end
def search(path, node = doc)
node.search(*ensure_xpath(path))
end
def at_xpath(path, node = doc)
node.at_xpath(*ensure_xpath(path))
end
def namespaces
@namespaces ||= doc.document.collect_namespaces
end
2011-03-10 22:45:21 +00:00
private
2011-03-23 18:10:02 +00:00
def current_namespaces
doc.document.collect_namespaces
end
2011-03-23 18:10:02 +00:00
def prefix_map
@prefix_map ||= Hash[current_namespaces.collect { |prefix, namespace|
self.class.get_required_namespace(namespace, prefix.gsub('xmlns:', ''))
}.compact]
end
2011-03-23 18:10:02 +00:00
def self.get_required_namespace(namespace, prefix)
result = nil
REQUIRED_NAMESPACES.each do |original_prefix, target_namespace|
result = [ original_prefix.to_s, prefix ] if namespace == target_namespace
end
result
end
2011-03-11 18:27:17 +00:00
def ensure_namespaces!
2011-03-23 18:10:02 +00:00
existing = current_namespaces
REQUIRED_NAMESPACES.each do |namespace, url|
doc.root.add_namespace_definition(namespace.to_s, url) if !existing.values.include?(url)
2011-03-11 18:27:17 +00:00
end
end
def ensure_descriptions_findable!
2011-03-15 14:55:09 +00:00
added = []
search('//rdf:Description').each do |description|
2011-03-11 18:27:17 +00:00
if first_child = description.first_element_child
2011-03-23 18:10:02 +00:00
if namespace = first_child.namespace
prefix = namespace.prefix
2011-03-15 14:55:09 +00:00
if prefix_description = PREFIXES[prefix_map.index(prefix)]
description[self % 'rdf:about'] = prefix_description
added << prefix
end
2011-03-11 18:27:17 +00:00
end
end
end
2011-03-15 14:55:09 +00:00
2011-03-23 18:10:02 +00:00
ensure_rdf!
ensure_missing_descriptions!(added)
end
2011-03-23 18:10:02 +00:00
def ensure_rdf!
doc.first_element_child.add_child(self % '<rdf:RDF />') if !at_xpath('//rdf:RDF')
end
2011-03-23 18:10:02 +00:00
def ensure_missing_descriptions!(already_added)
2011-03-15 14:55:09 +00:00
PREFIXES.each do |prefix, about|
2011-03-23 18:10:02 +00:00
if !already_added.include?(prefix)
at_xpath('//rdf:RDF').add_child(self % %{<rdf:Description rdf:about="#{about}" />})
2011-03-15 14:55:09 +00:00
end
end
2011-03-11 18:27:17 +00:00
end
2011-03-10 22:45:21 +00:00
def dublin_core
at_rdf_description "Dublin Core"
end
def iptc
at_rdf_description "IPTC"
end
2011-03-14 16:35:29 +00:00
def avm
at_rdf_description "AVM"
end
def photoshop
at_rdf_description "Photoshop"
end
2011-03-10 22:45:21 +00:00
def at_rdf_description(about)
AVM::Node.new(self, at_xpath(%{//rdf:Description[@rdf:about="#{about}"]}))
2011-03-10 22:45:21 +00:00
end
def empty_xml_doc
2011-03-11 18:27:17 +00:00
Nokogiri::XML(<<-XML)
2011-03-10 22:45:21 +00:00
<x:xmpmeta xmlns:x="adobe:ns:meta/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:RDF>
2011-03-15 14:55:09 +00:00
<rdf:Description rdf:about="Dublin Core" />
<rdf:Description rdf:about="IPTC" />
<rdf:Description rdf:about="Photoshop" />
<rdf:Description rdf:about="AVM" />
2011-03-10 22:45:21 +00:00
</rdf:RDF>
</x:xmpmeta>
XML
end
end
end