org.docx4j.model.datastorage.ValueInserterPlainTextForOpenAPI3 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of docx4j Show documentation
Show all versions of docx4j Show documentation
docx4j is a library which helps you to work with the Office Open
XML file format as used in docx
documents, pptx presentations, and xlsx spreadsheets.
package org.docx4j.model.datastorage;
import java.math.BigInteger;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import org.docx4j.XmlUtils;
import org.docx4j.jaxb.Context;
import org.docx4j.model.datastorage.BindingTraverserXSLT.BookmarkCounter;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.parts.JaxbXmlPart;
import org.docx4j.wml.CTBookmark;
import org.docx4j.wml.CTMarkupRange;
import org.docx4j.wml.RPr;
import org.docx4j.wml.Text;
import org.docx4j.wml.P.Hyperlink;
import org.docx4j.wml.R;
import org.opendope.xpaths.Xpaths;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
/**
* @author jharrop
* @6.0.1
*/
public class ValueInserterPlainTextForOpenAPI3 extends ValueInserterPlainTextImpl {
/*
In OpenAPI 3, a Reference Object is a simple object to allow referencing
other components in the specification, internally and externally.
The Reference Object is defined by JSON Reference and follows the same structure,
behavior and rules; reference resolution is accomplished as defined by the
JSON Reference specification
Here we add a bookmark around components, currently just schemas.
TODO: support other components (pretty trivial).
*/
private static Logger log = LoggerFactory.getLogger(ValueInserterPlainTextForOpenAPI3.class);
public DocumentFragment toOpenXml(Xpaths.Xpath.DataBinding dataBinding, RPr rPr, boolean multiLine, BookmarkCounter bookmarkCounter,
String val,
JaxbXmlPart sourcePart) throws Docx4JException {
try {
if (val==null || val.equals("")) {
return BindingTraverserXSLT.createPlaceholder(rPr, "p");
}
} catch (Exception e) {
throw new Docx4JException(e.getMessage(), e);
}
// Is this a component definition, which needs a bookmark?
// The challenge we have is that the incoming XPath will be something like:
// local-name(/yaml/components[1]/schemas[1]/*[2][1])
// (assume value Pets here)
// but we're wanting to generate a bookmark name
// components_schemas_Pets
// There may be a generalised way to tell whether 2 XPaths are the "same":
// given the node result each XPath produces when evaluated, can you get a canonical XPath to that node
// and are these the same? Or maybe each XPath returns the same node object?
// But here, we can use an easy to understand heuristic.
String bookmarkName = getBookmarkName(dataBinding.getXpath(), val);
if (bookmarkName==null) {
// Usual case
return super.toOpenXml(dataBinding, rPr, multiLine, bookmarkCounter, val, sourcePart);
}
org.w3c.dom.Document docContainer = XmlUtils.neww3cDomDocument();
DocumentFragment docfrag = docContainer.createDocumentFragment();
/*
Pets
*/
int id = bookmarkCounter.bookmarkId.get();
// w:bookmarkStart w:id=\"" + id + "\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" />" +
addBookmarkStart( bookmarkName, id, docfrag);
// the run
addRun( val, docfrag);
// " ";
addBookmarkEnd(id, docfrag);
// ready for next time
bookmarkCounter.bookmarkId.getAndIncrement();
return docfrag;
}
private void addRun(String val,
DocumentFragment docfrag) {
R r = new R();
Text t = new Text();
t.setValue(val);
r.getContent().add(t);
Document tmpDoc = XmlUtils.marshaltoW3CDomDocument(r);
XmlUtils.treeCopy(tmpDoc.getDocumentElement(), docfrag);
}
private void addBookmarkStart(String bookmarkName, int id,
DocumentFragment docfrag) {
CTBookmark bookmark = Context.getWmlObjectFactory().createCTBookmark();
JAXBElement bookmarkWrapped
= Context.getWmlObjectFactory().createPBookmarkStart(bookmark);
bookmark.setName( bookmarkName );
bookmark.setId( BigInteger.valueOf( id) );
Document tmpDoc = XmlUtils.marshaltoW3CDomDocument(bookmark);
XmlUtils.treeCopy(tmpDoc.getDocumentElement(), docfrag);
}
private void addBookmarkEnd(int id, DocumentFragment docfrag) {
CTMarkupRange markuprange = Context.getWmlObjectFactory().createCTMarkupRange();
markuprange.setId( BigInteger.valueOf(id ) );
Document tmpDoc = XmlUtils.marshaltoW3CDomDocument(markuprange);
XmlUtils.treeCopy(tmpDoc.getDocumentElement(), docfrag);
}
private final static String COMPONENT_SCHEMAS = "local-name(/yaml/components[1]/schemas[1]/";
private String getBookmarkName(String xpath, String val) {
// Given:
// local-name(/yaml/components[1]/schemas[1]/*[2][1])
// (assume value Pets here)
// return bookmark name
// components_schemas_Pets
if (xpath.startsWith(COMPONENT_SCHEMAS)) {
String substring = xpath.substring(COMPONENT_SCHEMAS.length());
if(substring.length()>0
&& !substring.contains("/")) {
return "components_schemas_" + val;
}
}
return null; // don't bookmark
}
protected void addHyperlinkToDocFrag(JaxbXmlPart sourcePart, DocumentFragment docfrag, String url) throws Docx4JException {
if (url.startsWith("http")
|| url.startsWith("mailto")) {
super.addHyperlinkToDocFrag(sourcePart, docfrag, url);
} else {
// Handle eg #/components/schemas/Pets
String bookmarkName = refToBookmarkName(url);
try {
Document tmpDoc = XmlUtils.marshaltoW3CDomDocument(
BindingHandler.getHyperlinkResolver().generateHyperlink(bookmarkName, url));
XmlUtils.treeCopy(tmpDoc.getDocumentElement(), docfrag);
} catch (JAXBException e) {
throw new Docx4JException(e.getMessage(), e);
}
}
}
private String refToBookmarkName(String ref) {
// INPUT eg: "#/components/schemas/Pets"
// OUTPUTS components_schemas_Pets
return ref.substring(2).replace("/", "_");
}
// public static void main(String[] args) throws Exception {
//
// String sub = "#/components/schemas/Pets".substring(2);
//
// System.out.println( sub.replace("/", "_")
// );
// }
}