w2phtml/source/java/writer2latex/base/BibliographyGenerator.java
henrikjust 44f4c68801 Change license to GPLv3
git-svn-id: svn://svn.code.sf.net/p/writer2latex/code/trunk@272 f0f2a975-2e09-46c8-9428-3b39399b9f3c
2018-03-06 20:06:05 +00:00

292 lines
9.8 KiB
Java

/************************************************************************
*
* BibliographyGenerator.java
*
* Copyright: 2002-2018 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2018-03-06)
*
*/
package writer2latex.base;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import writer2latex.office.OfficeReader;
import writer2latex.office.XMLString;
import writer2latex.util.Misc;
import writer2latex.util.StringComparator;
/** This class is used to generate bibliographic references and a bibliography.
* Bibliographies are generated from a list of items (text:bibliograpy-mark), a global configuration
* (text:bibliography-configuration) and a formatting template (text:bibliography-source)
*/
public abstract class BibliographyGenerator {
// Bibliography configuration data
private String sPrefix = "[";
private String sSuffix = "]";
// The sorted list of bibliography marks
private List<Element> bibMarkList = new ArrayList<Element>();
// Map from key to label
private Map<String,String> bibMarkLabel = new HashMap<String,String>();
// Flag to identify numbering
private boolean bNumberedEntries = false;
// Flag to identify truncation of templates
private boolean bSkipKey = false;
/** Create a new bibliography generator based on a bibliography configuration and a list of bibliography marks
*
* @param ofr the office reader used to access the source document
* @param bSkipKey set to true if the key should be excluded when applying templates
*/
protected BibliographyGenerator(OfficeReader ofr, boolean bSkipKey) {
this.bSkipKey = bSkipKey;
Element bibConfig = ofr.getBibliographyConfiguration();
if (bibConfig!=null) {
if (bibConfig.hasAttribute(XMLString.TEXT_PREFIX)) {
sPrefix = bibConfig.getAttribute(XMLString.TEXT_PREFIX);
}
if (bibConfig.hasAttribute(XMLString.TEXT_SUFFIX)) {
sSuffix = bibConfig.getAttribute(XMLString.TEXT_SUFFIX);
}
}
collectBibMarks(ofr.getBibliographyMarks());
sortBibMarks(bibConfig);
createLabels(bibConfig);
}
// Collect the bibliography marks from the raw list, removing any duplicates
private void collectBibMarks(List<Element> bibMarks) {
Set<String> keys = new HashSet<String>();
for (Element bibMark : bibMarks) {
String sKey = bibMark.getAttribute(XMLString.TEXT_IDENTIFIER);
if (!keys.contains(sKey)) {
bibMarkList.add(bibMark);
keys.add(sKey);
}
}
}
// Sort the bibliography marks based on the settings in the bibliography configuration
private void sortBibMarks(Element bibConfig) {
if (bibConfig!=null && "false".equals(bibConfig.getAttribute(XMLString.TEXT_SORT_BY_POSITION))) {
// Get the sort algorithm
//String sSortAlgorithm = "alphanumeric";
//if (bibConfig.hasAttribute(XMLString.TEXT_SORT_ALGORITHM)) {
// sSortAlgorithm = bibConfig.getAttribute(XMLString.TEXT_SORT_ALGORITHM);
//}
// Get the sort keys
List<String> sortKeys = new ArrayList<String>();
List<Boolean> sortAscending = new ArrayList<Boolean>();
Node child = bibConfig.getFirstChild();
while (child!=null) {
if (child.getNodeType()==Node.ELEMENT_NODE && child.getNodeName().equals(XMLString.TEXT_SORT_KEY)) {
String sKey = Misc.getAttribute(child, XMLString.TEXT_KEY);
if (sKey!=null) {
sortKeys.add(sKey);
sortAscending.add(!"false".equals(Misc.getAttribute(child, XMLString.TEXT_SORT_ASCENDING)));
}
}
child = child.getNextSibling();
}
// Sort the list
Comparator<Element> comparator = new StringComparator<Element>(
Misc.getAttribute(bibConfig,XMLString.FO_LANGUAGE),
Misc.getAttribute(bibConfig, XMLString.FO_COUNTRY)) {
private List<String> sortKeys = null;
private List<Boolean> sortAscending = null;
Comparator<Element> setSortKeys(List<String> sortKeys, List<Boolean> sortAscending) {
this.sortKeys = sortKeys;
this.sortAscending = sortAscending;
return this;
}
public int compare(Element a, Element b) {
int nCount = sortKeys.size();
for (int i=0; i<nCount; i++) {
String sWorda = a.getAttribute("text:"+sortKeys.get(i));
String sWordb = b.getAttribute("text:"+sortKeys.get(i));
int nCompare = getCollator().compare(sWorda, sWordb)*(sortAscending.get(i) ? 1 : -1);
if (nCompare!=0) { return nCompare; }
}
return 0;
}
}.setSortKeys(sortKeys, sortAscending);
Collections.sort(bibMarkList, comparator);
}
}
private void createLabels(Element bibConfig) {
bNumberedEntries = bibConfig!=null && "true".equals(bibConfig.getAttribute(XMLString.TEXT_NUMBERED_ENTRIES));
int nCount = bibMarkList.size();
for (int i=0; i<nCount; i++) {
Element item = bibMarkList.get(i);
String sKey = item.getAttribute(XMLString.TEXT_IDENTIFIER);
if (bNumberedEntries) {
bibMarkLabel.put(sKey, Integer.toString(i+1));
}
else {
bibMarkLabel.put(sKey, sKey);
}
}
}
/** Get all labels used in the bibliography
*
* @return the set of labels
*/
protected Collection<String> getLabels() {
return bibMarkLabel.values();
}
/** Check whether entries are numbered rather than labeled with the key
*
* @return true if the entries are numbered
*/
protected boolean isNumberedEntries() {
return bNumberedEntries;
}
/** Get citation text for a reference to the bibliography
*
* @param sKey the key of the bibliography item
* @return the citation text to be shown in the document
*/
public String generateCitation(String sKey) {
return sPrefix+bibMarkLabel.get(sKey)+sSuffix;
}
/** Generate a bibliography
*
* @param bibSource a text:bibliography-source element
*/
protected void generateBibliography(Element bibSource) {
Map<String,Element> bibEntryTemplate = collectTemplates(bibSource);
for (Element bibMark : bibMarkList) {
String sKey = bibMark.getAttribute(XMLString.TEXT_IDENTIFIER);
String sType = bibMark.getAttribute(XMLString.TEXT_BIBLIOGRAPHY_TYPE);
if (bibEntryTemplate.containsKey(sType)) {
Element template = bibEntryTemplate.get(sType);
String sStyleName = template.getAttribute(XMLString.TEXT_STYLE_NAME);
insertBibliographyItem(sStyleName,sKey);
applyTemplate(template,bibMark);
}
else { // Use a default template (identical with the default template in LO)
String sAuthor = bibMark.getAttribute(XMLString.TEXT_AUTHOR);
String sTitle = bibMark.getAttribute(XMLString.TEXT_TITLE);
String sYear = bibMark.getAttribute(XMLString.TEXT_YEAR);
insertBibliographyItem(null,sKey);
if (!bSkipKey) {
insertBibliographyItemElement(null,bibMarkLabel.get(sKey));
insertBibliographyItemElement(null,": ");
}
insertBibliographyItemElement(null,sAuthor);
insertBibliographyItemElement(null,", ");
insertBibliographyItemElement(null,sTitle);
insertBibliographyItemElement(null,", ");
insertBibliographyItemElement(null,sYear);
}
}
}
private Map<String,Element> collectTemplates(Element bibSource) {
Map<String,Element> bibEntryTemplate = new HashMap<String,Element>();
Node child = bibSource.getFirstChild();
while (child!=null) {
if (child.getNodeType()==Node.ELEMENT_NODE
&& child.getNodeName().equals(XMLString.TEXT_BIBLIOGRAPHY_ENTRY_TEMPLATE)) {
String sType = Misc.getAttribute(child, XMLString.TEXT_BIBLIOGRAPHY_TYPE);
if (sType!=null) {
bibEntryTemplate.put(sType, (Element)child);
}
}
child = child.getNextSibling();
}
return bibEntryTemplate;
}
private void applyTemplate(Element template, Element bibMark) {
boolean bSkip = bSkipKey;
Node child = template.getFirstChild();
while (child!=null) {
if (child.getNodeType()==Node.ELEMENT_NODE) {
if (child.getNodeName().equals(XMLString.TEXT_INDEX_ENTRY_BIBLIOGRAPHY)) {
String sField = Misc.getAttribute(child, XMLString.TEXT_BIBLIOGRAPHY_DATA_FIELD);
if (sField!=null) {
String sValue = bibMark.getAttribute("text:"+sField);
if (sField.equals("identifier")) {
sValue = bibMarkLabel.get(sValue);
}
else {
bSkip = false;
}
if (!bSkip) {
String sElementStyleName = Misc.getAttribute(child,XMLString.TEXT_STYLE_NAME);
insertBibliographyItemElement(sElementStyleName,sValue);
}
}
}
else if (child.getNodeName().equals(XMLString.TEXT_INDEX_ENTRY_SPAN)) {
if (!bSkip) {
String sValue = Misc.getPCDATA(child);
String sElementStyleName = Misc.getAttribute(child,XMLString.TEXT_STYLE_NAME);
insertBibliographyItemElement(sElementStyleName,sValue);
}
}
}
child = child.getNextSibling();
}
}
/** Insert a new bibliography item
*
* @param sStyleName a paragraph style to apply to the item
* @param sKey the key of the bibliography item
*/
protected abstract void insertBibliographyItem(String sStyleName, String sKey);
/** Insert an element of a bibliography item
*
* @param sStyleName a character style to apply to the element
* @param sText the element text
*/
protected abstract void insertBibliographyItemElement(String sStyleName, String sText);
}