1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
require "nokogiri"
# OpenTox module
module OpenTox
#Class for QMRF reporting.
#
#Provides a ruby OpenTox class to prepare an initial version of a QMRF report.
#The XML output is in QMRF version 1.3 and can be finalized with the QMRF editor 2.0 (https://sourceforge.net/projects/qmrf/)
#@example Report
# require "qsar-report"
# report = OpenTox::QMRFReport.new
# report.value "QSAR_title", "My QSAR Title"
# report.change_attributes "training_set_data", {:inchi => "Yes", :smiles => "Yes"}
# report.change_catalog :publications_catalog, :publications_catalog_1, {:title => "MyName M (2016) My Publication Title, QSAR News, 10, 14-22", :url => "http://myqsarnewsmag.dom"}
# report.ref_catalog :bibliography, :publications_catalog, :publications_catalog_1
# puts report.to_xml
class QMRFReport
# QMRF XML Schema file
SCHEMA_FILE = File.join(File.dirname(__FILE__),"template/qmrf.xsd")
# QMRF XML Template file
TEMPLATE_FILE = File.join(File.dirname(__FILE__),"template/qmrf.xml")
# QMRF catalogs. Entries of a catalog can be referenced in certain tags.
CATALOGS = ["software_catalog", "algorithms_catalog", "descriptors_catalog", "endpoints_catalog", "publications_catalog", "authors_catalog"]
# QMRF XML tags with attributes to edit
ATTRIBUTE_TAGS = ["training_set_availability", "training_set_data", "training_set_descriptors", "dependent_var_availability", "validation_set_availability", "validation_set_data", "validation_set_descriptors", "validation_dependent_var_availability"]
attr_accessor :xml, :report
# Open an existing QMRF xml report
# @param [String] file Name of the file
def open file
xml = File.read("#{file}")
@report = Nokogiri.XML(xml)
end
# Initialize a new report instance from qmrf template
def initialize
xml = File.read(TEMPLATE_FILE)
@report = Nokogiri.XML(xml)
end
# returns XML representation (QMRF XML report) of report instance
# @return [String] returns XML
def to_xml
@report.to_xml
end
# Get or Set a value
# e.G.:
#@example change the title
# report.value "QSAR_title", "Title of My QSAR"
# #changes the QSAR_title tag to:
# #<QSAR_title chapter="1.1" help="" name="QSAR identifier (title)">Title of My QSAR</QSAR_title>
# @param [String] key Nodename e.g.: "QSAR_title"
# @param [String] value Value to change. If not set the function returns the current value
# @return [Error] returns Error message if fails
# @return [String] returns value
def value key, value=nil
raise "Can not edit attribute #{key} directly. Edit the catalog with 'report.change_catalog(catalog, key, value)'." if ["QSAR_software","QSAR_Algorithm", ""].include? key
t = @report.at_css key
t.content = value unless value.nil?
t.content
end
# Set attributes of an report XML tag.
# Some of the QMRF XML tags have attributes to be edited. This applies to 6.1 to 6.4 and 7.1 to 7.4 see also: {OpenTox::QMRFReport::ATTRIBUTE_TAGS ATTRIBUTE_TAGS}.
# e.G. "Available information for the training set" at 6.2 of the report:
# <training_set_data cas="Yes" chapter="6.2" chemname="Yes" formula="Yes" help="" inchi="Yes" mol="Yes" name="Available information for the training set" smiles="Yes"/>
#@example change_attributes
# report.change_attributes "training_set_data", {:inchi => "Yes", :smiles => "Yes"}
# @param [String] tagname Nodename e.g.: "training_set_data"
# @param [Hash] valuehash Key-Value Hash of tag attributes to change.
# @return [Error] returns Error message if fails
def change_attributes tagname, valuehash
raise "Can not edit the attributes of tag: #{tagname}." unless ATTRIBUTE_TAGS.include? tagname
tag = @report.at_css tagname
valuehash.each do |key, value|
tag.attributes["#{key}"].value = value
end
end
# Change a catalog
# @param [String] catalog Name of the catalog - One of {OpenTox::QMRFReport::CATALOGS CATALOGS}.
# @param [String] id Single entry node in the catalog e.G.: "<software contact='mycontact@mydomain.dom' description="My QSAR Software " id="software_catalog_2" name="MySoftware" number="" url="https://mydomain.dom"/>
# @param [Hash] valuehash Key-Value Hash with attributes for a single catalog node
# @return [Error] returns Error message if fails
def change_catalog catalog, id, valuehash
catalog_exists? catalog
if @report.at_css("#{catalog}").at("[@id='#{id}']")
valuehash.each do |key, value|
@report.at_css("#{catalog}").at("[@id='#{id}']")["#{key}"]= value
end
else
cat = @report.at_css("#{catalog}")
newentry = Nokogiri::XML::Node.new("#{catalog.to_s.gsub(/s?_catalog/,'')}", self.report)
newentry["id"] = id
valuehash.each do |key, value|
newentry["#{key}"] = value
end
cat << newentry
end
end
# Set reference to a catalog entry.
# e.g.: reference an author entry from authors_catalog to Chapter 2.2 QMRF authors
#@example ref_catalog
# report.ref_catalog 'qmrf_authors', 'authors_catalog', 'firstauthor'
# @param [String] chapter Name of the chapter to add the catalog reference. e.g.: qmrf_authors, model_authors, QSAR_software, ...
# @param [String] catalog Name of the catalog. One of {OpenTox::QMRFReport::CATALOGS CATALOGS}.
# @param [String] id entry node in the catalog
def ref_catalog chapter, catalog, id
catalog_exists? catalog
if @report.at_css("#{catalog}").at("//*[@id='#{id}']")
chap = @report.at_css("#{chapter}")
if chap.at("[@idref='#{id}']").nil?
newentry = Nokogiri::XML::Node.new("#{catalog.to_s.gsub(/s?_catalog/,'_ref')}", self.report)
newentry["idref"] = id
chap << newentry
end
else
raise "catalog entry with id: #{id} do not exist."
end
end
# get an attribute from a catalog entry
# @param [String] catalog Name of the catalog. One of {OpenTox::QMRFReport::CATALOGS CATALOGS}.
# @param [String] id entry id in the catalog
# @param [String] key returns value of a key in a catalog node
# @return [String, false] returns value of a key in a catalog node or false if catalog entry do not exists.
def get_catalog_value catalog, id, key
catalog_exists? catalog
if @report.at_css("#{catalog}").at("[@id='#{id}']")
@report.at_css("#{catalog}").at("[@id='#{id}']")["#{key}"]
else
return false
end
end
# Check if a catalog exists in this QMRF version
# @param [String] catalog Catalog
# @return [Error, true] returns true or Error if a catalog do not exists. See also {OpenTox::QMRFReport::CATALOGS CATALOGS}.
def catalog_exists? catalog
raise "Unknown catalog: #{catalog}" unless CATALOGS.include? catalog.to_s
true
end
# Validates a report instance against qmrf.xsd (XML Structure Definition)
def validate
xsd = Nokogiri::XML::Schema(File.read(SCHEMA_FILE))
out = ""
xsd.validate(@report).each do |error|
out << error.message unless error.message == "Element 'algorithm', attribute 'publication_ref': '' is not a valid value of the atomic type 'xs:IDREF'." || error.message == "Element 'descriptor', attribute 'publication_ref': '' is not a valid value of the atomic type 'xs:IDREF'."
# @todo ignore case sensitivity error: error.message The value 'NO' is not an.Element of the set {'Yes', 'No'}.
end
return out
end
end
end
|