8babf5a4b89d9e29bea61178b1a106d3b68904c1
[debian/jabref.git] / src / java / net / sf / jabref / util / XMPSchemaBibtex.java
1 package net.sf.jabref.util;
2
3 import java.io.IOException;
4 import java.util.Arrays;
5 import java.util.Calendar;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.TreeSet;
11
12 import javax.xml.transform.TransformerException;
13
14 import net.sf.jabref.AuthorList;
15 import net.sf.jabref.BibtexDatabase;
16 import net.sf.jabref.BibtexEntry;
17 import net.sf.jabref.BibtexEntryType;
18 import net.sf.jabref.JabRefPreferences;
19 import net.sf.jabref.Util;
20
21 import org.jempbox.xmp.XMPMetadata;
22 import org.jempbox.xmp.XMPSchema;
23 import org.w3c.dom.Element;
24 import org.w3c.dom.NamedNodeMap;
25 import org.w3c.dom.Node;
26 import org.w3c.dom.NodeList;
27
28 public class XMPSchemaBibtex extends XMPSchema {
29
30         /**
31          * The namespace of this schema.
32          */
33         public static final String NAMESPACE = "http://jabref.sourceforge.net/bibteXMP/";
34
35         public static final String KEY = "bibtex";
36
37         /**
38          * Create a new empty XMPSchemaBibtex as a child in the given XMPMetadata.
39          * 
40          * @param parent
41          */
42         public XMPSchemaBibtex(XMPMetadata parent) {
43                 super(parent, KEY, NAMESPACE);
44         }
45
46         /**
47          * Create schema from an existing XML element.
48          * 
49          * @param element
50          *            The existing XML element.
51          */
52         public XMPSchemaBibtex(Element e, String namespace) {
53                 super(e, KEY);
54         }
55
56         protected String makeProperty(String propertyName) {
57                 return KEY + ":" + propertyName;
58         }
59
60         /**
61          * 
62          * @param field
63          * @return
64          * @derived Uses XMPSchema methods
65          */
66         public List getPersonList(String field) {
67                 return getSequenceList(field);
68         }
69
70         /**
71          * 
72          * @param field
73          * @param value
74          * @derived Uses XMPSchema methods
75          */
76         public void setPersonList(String field, String value) {
77                 AuthorList list = AuthorList.getAuthorList(value);
78
79                 int n = list.size();
80                 for (int i = 0; i < n; i++) {
81                         addSequenceValue(field, list.getAuthor(i).getFirstLast(false));
82                 }
83         }
84
85         public String getTextProperty(String field) {
86                 return super.getTextProperty(makeProperty(field));
87         }
88
89         public void setTextProperty(String field, String value) {
90                 super.setTextProperty(makeProperty(field), value);
91         }
92
93         public List getBagList(String bagName) {
94                 return super.getBagList(makeProperty(bagName));
95         }
96
97         public void removeBagValue(String bagName, String value) {
98                 super.removeBagValue(makeProperty(bagName), value);
99         }
100
101         public void addBagValue(String bagName, String value) {
102                 super.addBagValue(makeProperty(bagName), value);
103         }
104
105         public List getSequenceList(String seqName) {
106                 return super.getSequenceList(makeProperty(seqName));
107         }
108
109         public void removeSequenceValue(String seqName, String value) {
110                 super.removeSequenceValue(makeProperty(seqName), value);
111         }
112
113         public void addSequenceValue(String seqName, String value) {
114                 super.addSequenceValue(makeProperty(seqName), value);
115         }
116
117         public List getSequenceDateList(String seqName) throws IOException {
118                 return super.getSequenceDateList(makeProperty(seqName));
119         }
120
121         public void removeSequenceDateValue(String seqName, Calendar date) {
122                 super.removeSequenceDateValue(makeProperty(seqName), date);
123         }
124
125         public void addSequenceDateValue(String field, Calendar date) {
126                 super.addSequenceDateValue(makeProperty(field), date);
127         }
128
129         public static String getContents(NodeList seqList) {
130
131                 Element seqNode = (Element) seqList.item(0);
132                 StringBuffer seq = null;
133
134                 NodeList items = seqNode.getElementsByTagName("rdf:li");
135                 for (int j = 0; j < items.getLength(); j++) {
136                         Element li = (Element) items.item(j);
137                         if (seq == null) {
138                                 seq = new StringBuffer();
139                         } else {
140                                 seq.append(" and ");
141                         }
142                         seq.append(getTextContent(li));
143                 }
144                 if (seq != null) {
145                         return seq.toString();
146                 }
147                 return null;
148         }
149
150         /**
151          * Returns a map of all properties and their values. LIs and bags in seqs
152          * are concatenated using " and ".
153          * 
154          * @return Map from name of textproperty (String) to value (String). For
155          *         instance: "year" => "2005". Empty map if none found.
156          * @throws TransformerException
157          */
158         public static Map getAllProperties(XMPSchema schema, String namespaceName) {
159                 NodeList nodes = schema.getElement().getChildNodes();
160
161                 Map<String, String> result = new HashMap<String, String>();
162
163                 if (nodes == null) {
164                         return result;
165                 }
166
167                 // Check child-nodes first
168                 int n = nodes.getLength();
169
170                 for (int i = 0; i < n; i++) {
171                         Node node = nodes.item(i);
172                         if (node.getNodeType() != Node.ATTRIBUTE_NODE
173                                 && node.getNodeType() != Node.ELEMENT_NODE)
174                                 continue;
175
176                         String nodeName = node.getNodeName();
177
178                         String[] split = nodeName.split(":");
179
180                         if (split.length == 2 && split[0].equals(namespaceName)) {
181                                 NodeList seqList = ((Element) node).getElementsByTagName("rdf:Seq");
182                                 if (seqList.getLength() > 0) {
183
184                                         String seq = getContents(seqList);
185
186                                         if (seq != null) {
187                                                 result.put(split[1], seq);
188                                         }
189                                 } else {
190                                         NodeList bagList = ((Element) node).getElementsByTagName("rdf:Bag");
191                                         if (bagList.getLength() > 0) {
192
193                                                 String seq = getContents(bagList);
194
195                                                 if (seq != null) {
196                                                         result.put(split[1], seq);
197                                                 }
198                                         } else {
199                                                 result.put(split[1], getTextContent(node));
200                                         }
201                                 }
202                         }
203                 }
204
205                 // Then check Attributes
206                 NamedNodeMap attrs = schema.getElement().getAttributes();
207                 int m = attrs.getLength();
208                 for (int j = 0; j < m; j++) {
209                         Node attr = attrs.item(j);
210
211                         String nodeName = attr.getNodeName();
212                         String[] split = nodeName.split(":");
213                         if (split.length == 2 && split[0].equals(namespaceName)) {
214                                 result.put(split[1], attr.getNodeValue());
215                         }
216                 }
217
218                 /*
219                  * Collapse Whitespace
220                  * 
221                  * Quoting from
222                  * http://www.gerg.ca/software/btOOL/doc/bt_postprocess.html: <cite>
223                  * "The exact rules for collapsing whitespace are simple: non-space
224                  * whitespace characters (tabs and newlines mainly) are converted to
225                  * space, any strings of more than one space within are collapsed to a
226                  * single space, and any leading or trailing spaces are deleted."
227                  * </cite>
228                  */
229                 
230                 for (Map.Entry<String, String> entry : result.entrySet()){
231                         String key = entry.getKey();
232                         if (preserveWhiteSpace.contains(key))
233                                 continue;
234                         entry.setValue(((String) entry.getValue()).replaceAll("\\s+", " ").trim());
235                 }
236
237                 return result;
238         }
239
240         public static HashSet<String> preserveWhiteSpace = new HashSet<String>();
241         static {
242                 preserveWhiteSpace.add("abstract");
243                 preserveWhiteSpace.add("note");
244                 preserveWhiteSpace.add("review");
245         }
246
247         public void setBibtexEntry(BibtexEntry entry) {
248                 setBibtexEntry(entry, null);
249         }
250         
251         /**
252          * 
253          * @param entry
254          * @param database maybenull
255          */
256         public void setBibtexEntry(BibtexEntry entry, BibtexDatabase database) {
257                 // Set all the values including key and entryType
258                 Object[] fields = entry.getAllFields();
259                 Object[] results;
260                 int resultsSize;
261                 
262                 JabRefPreferences prefs = JabRefPreferences.getInstance();
263                 if (prefs.getBoolean("useXmpPrivacyFilter")) {
264                         TreeSet<String> filters = new TreeSet<String>(Arrays.asList(prefs.getStringArray("xmpPrivacyFilter")));
265                         results = new Object[fields.length];
266                         resultsSize = 0;
267                         for (int i = 0; i < fields.length; i++) {
268                                 if (!filters.contains(fields[i])) {
269                                         results[resultsSize++] = fields[i];
270                                 }
271                         }
272                 } else {
273                         results = fields;
274                         resultsSize = fields.length;
275                 }
276                 
277                 for (int i = 0; i < resultsSize; i++){
278                         String field = results[i].toString();
279                         String value = BibtexDatabase.getResolvedField(field, entry, database);
280                         if (field.equals("author") || field.equals("editor")) {
281                                 setPersonList(field, value);
282                         } else {
283                                 setTextProperty(field, value);
284                         }
285                 }
286                 setTextProperty("entrytype", entry.getType().getName());
287         }
288
289         public BibtexEntry getBibtexEntry() {
290
291                 String type = getTextProperty("entrytype");
292                 BibtexEntryType t;
293                 if (type != null)
294                         t = BibtexEntryType.getStandardType(type);
295                 else
296                         t = BibtexEntryType.OTHER;
297
298                 BibtexEntry e = new BibtexEntry(Util.createNeutralId(), t);
299
300                 // Get Text Properties
301                 Map text = getAllProperties(this, "bibtex");
302                 text.remove("entrytype");
303                 e.setField(text);
304                 return e;
305         }
306
307         /**
308          * Taken from DOM2Utils.java:
309          * 
310          * JBoss, the OpenSource EJB server
311          * 
312          * Distributable under LGPL license. See terms of license at gnu.org.
313          */
314         public static String getTextContent(Node node) {
315                 boolean hasTextContent = false;
316                 StringBuffer buffer = new StringBuffer();
317                 NodeList nlist = node.getChildNodes();
318                 for (int i = 0; i < nlist.getLength(); i++) {
319                         Node child = nlist.item(i);
320                         if (child.getNodeType() == Node.TEXT_NODE) {
321                                 buffer.append(child.getNodeValue());
322                                 hasTextContent = true;
323                         }
324                 }
325                 return (hasTextContent ? buffer.toString() : "");
326         }
327
328 }