205 lines
7.5 KiB
C
205 lines
7.5 KiB
C
/*
|
|
* xml.c - Create XML representation of sermon document
|
|
* Copyright © 2017 David A. Baer
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the organization nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY David A. Baer ''AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL David A. Baer BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
#include <libxml/tree.h>
|
|
#include <string.h>
|
|
#include "options.h"
|
|
#include "sermon.h"
|
|
|
|
static xmlNsPtr srmNs = NULL;
|
|
|
|
static void
|
|
appendHeaderNode(xmlNsPtr sermon_ns, xmlNodePtr headerNode,
|
|
const char* headerName, const char* headerText) {
|
|
if (headerText) {
|
|
xmlNodePtr ptr = xmlNewNode(sermon_ns, headerName);
|
|
xmlAddChild(ptr, xmlNewText(headerText));
|
|
xmlAddChild(headerNode, ptr);
|
|
}
|
|
}
|
|
|
|
xmlNodePtr
|
|
sermonHeader(xmlNsPtr sermon_ns, const Sermon* srm) {
|
|
xmlNodePtr header = xmlNewNode(sermon_ns, "header");
|
|
appendHeaderNode(sermon_ns, header, "title", srm->sermonTitle);
|
|
appendHeaderNode(sermon_ns, header, "author", srm->sermonAuthor ? srm->sermonAuthor : options.authorName);
|
|
appendHeaderNode(sermon_ns, header, "occasion", srm->sermonOccasion);
|
|
appendHeaderNode(sermon_ns, header, "place", srm->sermonPlace ? srm->sermonPlace : options.placeName);
|
|
appendHeaderNode(sermon_ns, header, "date", srm->sermonDate);
|
|
appendHeaderNode(sermon_ns, header, "text", srm->sermonText);
|
|
return header;
|
|
}
|
|
|
|
int
|
|
findReferenceNumber(
|
|
int numReferences,
|
|
const SermonReference* sermonReferencesPtr,
|
|
const char* refId) {
|
|
int i;
|
|
for (i = 0; i < numReferences; i++) {
|
|
if (strcmp(sermonReferencesPtr[i].refId, refId) == 0) {
|
|
return i + 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
formatElementsToXML(
|
|
xmlNsPtr sermon_ns,
|
|
xmlNodePtr parentElement,
|
|
const FormatElement* a,
|
|
int length,
|
|
int numReferences,
|
|
const SermonReference* sermonReferencesPtr) {
|
|
int i = 0;
|
|
for (i = 0; i < length; i++) {
|
|
if (a[i].elementType == FORMAT_EM) {
|
|
xmlNodePtr em = xmlNewNode(sermon_ns, "em");
|
|
formatElementsToXML(sermon_ns, em, a[i].elementContent.nestedContent, a[i].elementContentLength, numReferences, sermonReferencesPtr);
|
|
xmlAddChild(parentElement, em);
|
|
} else if (a[i].elementType == FORMAT_TEXT) {
|
|
xmlAddChild(parentElement, xmlNewText(a[i].elementContent.textContent));
|
|
} else if (a[i].elementType == FORMAT_GREEK) {
|
|
xmlNodePtr greek = xmlNewNode(sermon_ns, "greek");
|
|
xmlAddChild(greek, xmlNewText(a[i].elementContent.textContent));
|
|
xmlAddChild(parentElement, greek);
|
|
} else if (a[i].elementType == FORMAT_UNICODE) {
|
|
xmlNodePtr unicode = xmlNewNode(sermon_ns, "unicode");
|
|
xmlAddChild(unicode, xmlNewText(a[i].elementContent.textContent));
|
|
xmlAddChild(parentElement, unicode);
|
|
} else if (a[i].elementType == FORMAT_URL) {
|
|
xmlNodePtr link = xmlNewNode(sermon_ns, "link");
|
|
xmlSetProp(link, "href", a[i].elementContent.textContent);
|
|
xmlAddChild(link, xmlNewText(a[i].elementContent.textContent));
|
|
xmlAddChild(parentElement, link);
|
|
} else if (a[i].elementType == FORMAT_CITATION) {
|
|
xmlNodePtr cite = xmlNewNode(sermon_ns, "cite");
|
|
int num = findReferenceNumber(numReferences, sermonReferencesPtr, a[i].elementContent.textContent);
|
|
if (num == 0) {
|
|
fprintf(stderr, "WARNING: reference %s not found -- omitted\n", a[i].elementContent.textContent);
|
|
} else {
|
|
char n[24];
|
|
snprintf(n, 24, "%d", num);
|
|
xmlNewProp(cite, "number", n);
|
|
xmlAddChild(parentElement, cite);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static xmlNodePtr
|
|
paragraphToXML(
|
|
xmlNsPtr sermon_ns,
|
|
const SermonParagraph* p,
|
|
int numReferences,
|
|
const SermonReference* sermonReferencesPtr) {
|
|
xmlNodePtr result = xmlNewNode(sermon_ns, "p");
|
|
formatElementsToXML(
|
|
sermon_ns,
|
|
result,
|
|
p->paraContent,
|
|
p->paraContentLength,
|
|
numReferences,
|
|
sermonReferencesPtr
|
|
);
|
|
return result;
|
|
}
|
|
|
|
xmlNodePtr
|
|
sermonBody(xmlNsPtr sermon_ns, const Sermon* srm) {
|
|
xmlNodePtr body = xmlNewNode(sermon_ns, "body");
|
|
xmlNodePtr block = NULL;
|
|
int i = 0;
|
|
for (i = 0; i < srm->numParagraphs; i++) {
|
|
const SermonParagraph* p = &srm->sermonParagraphs[i];
|
|
xmlNodePtr para = paragraphToXML(
|
|
sermon_ns, p, srm->numReferences, srm->sermonReferences
|
|
);
|
|
if (p->paraType == PARA_BLOCKQUOTE) {
|
|
if (!block) {
|
|
block = xmlNewNode(sermon_ns, "quote");
|
|
xmlAddChild(body, block);
|
|
}
|
|
xmlAddChild(block, para);
|
|
} else {
|
|
block = NULL;
|
|
xmlAddChild(body, para);
|
|
}
|
|
}
|
|
return body;
|
|
}
|
|
|
|
xmlNodePtr
|
|
sermonFooter(xmlNsPtr sermon_ns, const Sermon* srm) {
|
|
xmlNodePtr footer = xmlNewNode(sermon_ns, "footer");
|
|
int i = 0;
|
|
char num[10];
|
|
for (i = 0; i < srm->numReferences; i++) {
|
|
const SermonReference* r = &srm->sermonReferences[i];
|
|
xmlNodePtr ref = xmlNewNode(sermon_ns, "ref");
|
|
snprintf(num, 10, "%d", i + 1);
|
|
xmlNewProp(ref, "number", num);
|
|
xmlAddChild(ref, paragraphToXML(sermon_ns, &r->refText, srm->numReferences, srm->sermonReferences));
|
|
xmlAddChild(footer, ref);
|
|
}
|
|
return footer;
|
|
}
|
|
|
|
xmlDocPtr
|
|
sermonToXmlDoc(const Sermon* srm) {
|
|
/* document creation and setup */
|
|
xmlDocPtr document = xmlNewDoc("1.0");
|
|
xmlDtdPtr dtd = xmlCreateIntSubset(document, "sermon", NULL, "file://" DATADIR "/sermon.dtd");
|
|
xmlNodePtr sermon = xmlNewNode(NULL, "sermon");
|
|
xmlNsPtr sermon_ns = xmlNewNs(sermon, "urn:david-sermon", NULL);
|
|
xmlDocSetRootElement(document, sermon);
|
|
xmlSetNs(sermon, sermon_ns);
|
|
|
|
/* add header */
|
|
xmlAddChild(sermon, sermonHeader(sermon_ns, srm));
|
|
|
|
/* add body paragraphs */
|
|
xmlAddChild(sermon, sermonBody(sermon_ns, srm));
|
|
|
|
if (srm->numReferences) {
|
|
/* add footer */
|
|
xmlAddChild(sermon, sermonFooter(sermon_ns, srm));
|
|
}
|
|
|
|
return document;
|
|
}
|
|
|
|
void
|
|
printXML(xmlDocPtr document) {
|
|
xmlCharEncodingHandlerPtr encoding = xmlFindCharEncodingHandler("utf-8");
|
|
xmlOutputBufferPtr output = xmlOutputBufferCreateFd(1, encoding);
|
|
xmlSaveFileTo(output, document, "utf-8");
|
|
}
|
|
|