Xproc search and replace
Added custom extension for calabash to handle search and replace functionality. Added xproc pipeline/step to pick pom filename configuration and call calabash extension java code. Linked xproc and calabash extension using the configuration.xml
This commit is contained in:
@@ -147,6 +147,13 @@ public abstract class PDFMojo extends AbstractFoMojo {
|
|||||||
* default-value=""
|
* default-value=""
|
||||||
*/
|
*/
|
||||||
private String canonicalUrlBase;
|
private String canonicalUrlBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @parameter
|
||||||
|
* expression="${generate-pdf.replacementsFile}"
|
||||||
|
* default-value=""
|
||||||
|
*/
|
||||||
|
private String replacementsFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -380,7 +387,10 @@ public abstract class PDFMojo extends AbstractFoMojo {
|
|||||||
}
|
}
|
||||||
transformer.setParameter("branding", branding);
|
transformer.setParameter("branding", branding);
|
||||||
|
|
||||||
transformer.setParameter("docbook.infile",sourceDocBook.getAbsolutePath());
|
//transformer.setParameter("docbook.infile",sourceDocBook.getAbsolutePath());
|
||||||
|
String srcFilename = sourceDocBook.getName();
|
||||||
|
getLog().info("SOURCE FOR COVER PAGE: "+this.projectBuildDirectory+"/docbkx/"+srcFilename);
|
||||||
|
transformer.setParameter("docbook.infile", this.projectBuildDirectory+"/docbkx/"+srcFilename);
|
||||||
transformer.transform (new StreamSource(coverImageTemplate), new StreamResult(coverImage));
|
transformer.transform (new StreamSource(coverImageTemplate), new StreamResult(coverImage));
|
||||||
}
|
}
|
||||||
catch (TransformerConfigurationException e)
|
catch (TransformerConfigurationException e)
|
||||||
@@ -406,8 +416,10 @@ public abstract class PDFMojo extends AbstractFoMojo {
|
|||||||
|
|
||||||
map.put("security", security);
|
map.put("security", security);
|
||||||
map.put("canonicalUrlBase", canonicalUrlBase);
|
map.put("canonicalUrlBase", canonicalUrlBase);
|
||||||
|
map.put("replacementsFile", replacementsFile);
|
||||||
map.put("failOnValidationError", failOnValidationError);
|
map.put("failOnValidationError", failOnValidationError);
|
||||||
map.put("project.build.directory", this.projectBuildDirectory);
|
map.put("project.build.directory", this.projectBuildDirectory);
|
||||||
|
map.put("inputSrcFile", inputFilename);
|
||||||
//String outputDir=System.getProperty("project.build.outputDirectory ");
|
//String outputDir=System.getProperty("project.build.outputDirectory ");
|
||||||
return CalabashHelper.createSource(source, pathToPipelineFile, map);
|
return CalabashHelper.createSource(source, pathToPipelineFile, map);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,233 @@
|
|||||||
|
package com.rackspace.cloud.api.docs;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import net.sf.saxon.s9api.QName;
|
||||||
|
import net.sf.saxon.s9api.SaxonApiException;
|
||||||
|
import net.sf.saxon.s9api.XdmNode;
|
||||||
|
|
||||||
|
import org.apache.maven.plugin.logging.Log;
|
||||||
|
import org.apache.maven.plugin.logging.SystemStreamLog;
|
||||||
|
|
||||||
|
import com.xmlcalabash.core.XProcRuntime;
|
||||||
|
import com.xmlcalabash.io.ReadablePipe;
|
||||||
|
import com.xmlcalabash.io.WritablePipe;
|
||||||
|
import com.xmlcalabash.library.DefaultStep;
|
||||||
|
import com.xmlcalabash.model.RuntimeValue;
|
||||||
|
import com.xmlcalabash.runtime.XAtomicStep;
|
||||||
|
import com.xmlcalabash.util.ProcessMatch;
|
||||||
|
import com.xmlcalabash.util.ProcessMatchingNodes;
|
||||||
|
|
||||||
|
public class ReplaceTextXProcStep extends DefaultStep {
|
||||||
|
private static final QName _replacements_file = new QName("", "replacements.file");
|
||||||
|
private static Pattern XPATH_LINE = Pattern.compile("^XPATH=(.+)$");
|
||||||
|
private static Pattern COMMENT_LINE = Pattern.compile("^#(.+)$");
|
||||||
|
private static Pattern REPLACEMENT_LINE = Pattern.compile("(.+)->(.*)");
|
||||||
|
|
||||||
|
private ReadablePipe source = null;
|
||||||
|
private WritablePipe result = null;
|
||||||
|
private ProcessMatch matcher = null;
|
||||||
|
|
||||||
|
private Log log = null;
|
||||||
|
|
||||||
|
public Log getLog()
|
||||||
|
{
|
||||||
|
if ( log == null )
|
||||||
|
{
|
||||||
|
log = new SystemStreamLog();
|
||||||
|
}
|
||||||
|
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ReplaceTextXProcStep(XProcRuntime runtime, XAtomicStep step) {
|
||||||
|
super(runtime,step);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInput(String port, ReadablePipe pipe) {
|
||||||
|
source = pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOutput(String port, WritablePipe pipe) {
|
||||||
|
result = pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
source.resetReader();
|
||||||
|
result.resetWriter();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() throws SaxonApiException {
|
||||||
|
super.run();
|
||||||
|
|
||||||
|
List<XPathReplacement> replacements = readReplacementsFile(getOption(_replacements_file, "replacements.config"));
|
||||||
|
XdmNode updatedDoc = makeReplacements (source.read(), replacements);
|
||||||
|
|
||||||
|
result.write(updatedDoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<XPathReplacement> readReplacementsFile(String fileName) {
|
||||||
|
List<XPathReplacement> xpathReplacements = new ArrayList<XPathReplacement>();
|
||||||
|
XPathReplacement currentXPath = new XPathReplacement("//text()");
|
||||||
|
|
||||||
|
File replacementsFile = new File(fileName);
|
||||||
|
long fileLength = replacementsFile.length();
|
||||||
|
if(fileLength>0){
|
||||||
|
BufferedReader br = null;
|
||||||
|
try {
|
||||||
|
getLog().info("REPLACEMENTS FILE = " + replacementsFile.getAbsolutePath());
|
||||||
|
br = new BufferedReader(new FileReader(replacementsFile));
|
||||||
|
|
||||||
|
String line;
|
||||||
|
while((line = br.readLine()) != null) {
|
||||||
|
Matcher xpathLine = XPATH_LINE.matcher(line);
|
||||||
|
Matcher commentLine = COMMENT_LINE.matcher(line);
|
||||||
|
Matcher replacementLine = REPLACEMENT_LINE.matcher(line);
|
||||||
|
if (xpathLine.matches()) {
|
||||||
|
currentXPath = new XPathReplacement(xpathLine.group(1).trim());
|
||||||
|
xpathReplacements.add(currentXPath);
|
||||||
|
} else if (commentLine.matches()) {
|
||||||
|
/*ignore comment line.
|
||||||
|
* Although this could have been handled in the default else below.
|
||||||
|
* Had to create an explicit case here so that any reference to the token separator "->"
|
||||||
|
* in comments does not cause any issues.
|
||||||
|
*/
|
||||||
|
} else if (replacementLine.matches()) {
|
||||||
|
currentXPath.add(replacementLine.group(1).trim(), replacementLine.group(2).trim());
|
||||||
|
} else {
|
||||||
|
//ignore input line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xpathReplacements.size()==0) {
|
||||||
|
getLog().info("SKIPPING REPLACEMENTS: Replacements file is empty or was not found at specified location '"+fileName+ "'.");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
getLog().error("Unable to process replacements config file", e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
br.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
getLog().error("Unable to release/close replacements config file", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
getLog().info("SKIPPING REPLACEMENTS: Replacements file is empty or was not found at specified location '"+fileName+ "'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return xpathReplacements;
|
||||||
|
}
|
||||||
|
|
||||||
|
private XdmNode makeReplacements(XdmNode doc, List<XPathReplacement> replacements) {
|
||||||
|
for (XPathReplacement xpathRepl : replacements) {
|
||||||
|
matcher = new ProcessMatch(runtime, xpathRepl);
|
||||||
|
xpathRepl.setMatcher(matcher);
|
||||||
|
|
||||||
|
matcher.match(doc, new RuntimeValue(xpathRepl.getXPath()));
|
||||||
|
doc = matcher.getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class XPathReplacement implements Iterable<Replacement>, ProcessMatchingNodes {
|
||||||
|
String xpath;
|
||||||
|
List<Replacement> replacements;
|
||||||
|
ProcessMatch matcher;
|
||||||
|
|
||||||
|
public XPathReplacement(String _xpath) {
|
||||||
|
this.xpath = _xpath;
|
||||||
|
replacements = new ArrayList<Replacement>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getXPath() {
|
||||||
|
return xpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMatcher (ProcessMatch matcher) {
|
||||||
|
this.matcher = matcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(String oldVal, String newVal) {
|
||||||
|
replacements.add(new Replacement(oldVal, newVal));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String computeReplacement(XdmNode node) {
|
||||||
|
String newValue = node.getStringValue();
|
||||||
|
for (Replacement repl : this.replacements) {
|
||||||
|
if(repl.oldValue.startsWith("\"") && repl.oldValue.endsWith("\"")) {
|
||||||
|
newValue = (newValue.replace(repl.oldValue.substring(1,repl.oldValue.length()-1), repl.newValue));
|
||||||
|
} else {
|
||||||
|
newValue = (newValue.replaceAll(repl.oldValue, repl.newValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Replacement> iterator() {
|
||||||
|
return replacements.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean processStartDocument(XdmNode node) throws SaxonApiException {
|
||||||
|
return true;//process children
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processEndDocument(XdmNode node) throws SaxonApiException {
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean processStartElement(XdmNode node) throws SaxonApiException {
|
||||||
|
return true;//process children
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processAttribute(XdmNode node) throws SaxonApiException {
|
||||||
|
String newValue = computeReplacement(node);
|
||||||
|
matcher.addAttribute(node, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processEndElement(XdmNode node) throws SaxonApiException { }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processText(XdmNode node) throws SaxonApiException {
|
||||||
|
String newValue = computeReplacement(node);
|
||||||
|
matcher.addText(newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processComment(XdmNode node) throws SaxonApiException {
|
||||||
|
String newValue = computeReplacement(node);
|
||||||
|
matcher.addText(newValue);}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processPI(XdmNode node) throws SaxonApiException {
|
||||||
|
String newValue = computeReplacement(node);
|
||||||
|
matcher.addText(newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Replacement {
|
||||||
|
public String oldValue;
|
||||||
|
public String newValue;
|
||||||
|
|
||||||
|
public Replacement(String _oldVal, String _newVal) {
|
||||||
|
this.oldValue = _oldVal;
|
||||||
|
this.newValue = _newVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -158,6 +158,13 @@ public abstract class WebHelpMojo extends AbstractWebhelpMojo {
|
|||||||
*/
|
*/
|
||||||
private String canonicalUrlBase;
|
private String canonicalUrlBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @parameter
|
||||||
|
* expression="${generate-webhelp.replacementsFile}"
|
||||||
|
* default-value=""
|
||||||
|
*/
|
||||||
|
private String replacementsFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @parameter
|
* @parameter
|
||||||
@@ -405,8 +412,10 @@ public abstract class WebHelpMojo extends AbstractWebhelpMojo {
|
|||||||
|
|
||||||
map.put("security", this.security);
|
map.put("security", this.security);
|
||||||
map.put("canonicalUrlBase", this.canonicalUrlBase);
|
map.put("canonicalUrlBase", this.canonicalUrlBase);
|
||||||
|
map.put("replacementsFile", this.replacementsFile);
|
||||||
map.put("failOnValidationError", this.failOnValidationError);
|
map.put("failOnValidationError", this.failOnValidationError);
|
||||||
map.put("project.build.directory", this.projectBuildDirectory);
|
map.put("project.build.directory", this.projectBuildDirectory);
|
||||||
|
map.put("inputSrcFile", inputFilename);
|
||||||
|
|
||||||
int lastSlash=inputFilename.lastIndexOf("/");
|
int lastSlash=inputFilename.lastIndexOf("/");
|
||||||
|
|
||||||
|
|||||||
@@ -254,5 +254,9 @@
|
|||||||
|
|
||||||
<implementation type="cxu:compare"
|
<implementation type="cxu:compare"
|
||||||
class-name="com.xmlcalabash.extensions.xmlunit.Compare" />
|
class-name="com.xmlcalabash.extensions.xmlunit.Compare" />
|
||||||
|
|
||||||
|
<!-- Rackspace Extensions -->
|
||||||
|
<implementation type="cx:replace-text"
|
||||||
|
class-name="com.rackspace.cloud.api.docs.ReplaceTextXProcStep" />
|
||||||
|
|
||||||
</xproc-config>
|
</xproc-config>
|
||||||
|
|||||||
@@ -406,6 +406,59 @@
|
|||||||
</p:group>
|
</p:group>
|
||||||
</p:declare-step>
|
</p:declare-step>
|
||||||
|
|
||||||
|
<p:declare-step
|
||||||
|
xmlns:l="http://xproc.org/library"
|
||||||
|
xml:id="search-and-replace"
|
||||||
|
xmlns:c="http://www.w3.org/ns/xproc-step"
|
||||||
|
type="l:search-and-replace"
|
||||||
|
name="search-and-replace-step">
|
||||||
|
<p:input port="source" primary="true" sequence="true"/>
|
||||||
|
<p:output port="result" sequence="true">
|
||||||
|
<p:pipe step="group" port="result"/>
|
||||||
|
</p:output>
|
||||||
|
|
||||||
|
<p:input port="parameters" kind="parameter"/>
|
||||||
|
<ut:parameters name="params"/>
|
||||||
|
<p:sink/>
|
||||||
|
|
||||||
|
<p:group name="group">
|
||||||
|
<p:output port="result" primary="true">
|
||||||
|
<p:pipe step="replace" port="result"/>
|
||||||
|
</p:output>
|
||||||
|
|
||||||
|
<p:variable name="inputSrcFile" select="//c:param[@name = 'inputSrcFile']/@value">
|
||||||
|
<p:pipe step="params" port="parameters"/>
|
||||||
|
</p:variable>
|
||||||
|
<p:variable name="project.build.directory" select="//c:param[@name = 'project.build.directory']/@value">
|
||||||
|
<p:pipe step="params" port="parameters"/>
|
||||||
|
</p:variable>
|
||||||
|
<p:variable name="replacementsFile" select="//c:param[@name = 'replacementsFile']/@value">
|
||||||
|
<p:pipe step="params" port="parameters"/>
|
||||||
|
</p:variable>
|
||||||
|
<cx:replace-text name="replace">
|
||||||
|
<p:input port="source">
|
||||||
|
<p:pipe step="search-and-replace-step" port="source"/>
|
||||||
|
</p:input>
|
||||||
|
<p:with-option name="replacements.file" select="$replacementsFile">
|
||||||
|
</p:with-option>
|
||||||
|
</cx:replace-text>
|
||||||
|
<p:store encoding="utf-8" indent="true" omit-xml-declaration="false">
|
||||||
|
<p:with-option name="href"
|
||||||
|
select="concat('file://',$project.build.directory,'/docbkx/',$inputSrcFile)"
|
||||||
|
/>
|
||||||
|
</p:store>
|
||||||
|
</p:group>
|
||||||
|
</p:declare-step>
|
||||||
|
|
||||||
|
<!-- Search and replace calabash extension -->
|
||||||
|
<p:declare-step
|
||||||
|
type="cx:replace-text"
|
||||||
|
xml:id="replace-text">
|
||||||
|
<p:input port="source" primary="true" sequence="true"/>
|
||||||
|
<p:output port="result" primary="true" sequence="true"/>
|
||||||
|
<p:option name="replacements.file" cx:type="xsd:string"/>
|
||||||
|
</p:declare-step>
|
||||||
|
|
||||||
<!--+========================================================+
|
<!--+========================================================+
|
||||||
| Step parameters
|
| Step parameters
|
||||||
|
|
|
|
||||||
@@ -430,5 +483,4 @@
|
|||||||
</p:input>
|
</p:input>
|
||||||
</p:parameters>
|
</p:parameters>
|
||||||
</p:declare-step>
|
</p:declare-step>
|
||||||
|
|
||||||
</p:library>
|
</p:library>
|
||||||
@@ -48,6 +48,11 @@
|
|||||||
|
|
||||||
<l:extensions-info/>
|
<l:extensions-info/>
|
||||||
|
|
||||||
|
<cx:message>
|
||||||
|
<p:with-option name="message" select="'Making replacements'"/>
|
||||||
|
</cx:message>
|
||||||
|
<l:search-and-replace/>
|
||||||
|
|
||||||
<cx:message>
|
<cx:message>
|
||||||
<p:with-option name="message" select="'Normalize wadls'"/>
|
<p:with-option name="message" select="'Normalize wadls'"/>
|
||||||
</cx:message>
|
</cx:message>
|
||||||
|
|||||||
Reference in New Issue
Block a user