我使用Apache FOP 2.8將Apache FOP Intermediate Format (IF)文件轉換成帶有自己編寫的xslt樣式表的HTML文件。
作為外部庫,我目前只安裝了saxon12he。
問題#1(圖像到base64) 在源IF文檔中,有如下所示的圖像xml元素:
<image xlink:href="files\Logo.png"/>
很容易將它轉換成HTML并得到如下輸出
<img src="files\Logo.png"/>
當使用如下模板時:
<xsl:template match="image">
<xsl:variable name="file-path"><xsl:value-of select="@xlink:href"/></xsl:variable>
<img src="{$file-path}"/>
</xsl:template>
這里的問題是生成的HTML文件不能是“獨立的”...意味著除了HTML-file之外,還必須有一個包含Logo.png的文件目錄,這樣HTML-file才能找到imagepath files\Logo.png
但是我想要實現的是HTML文件是“獨立的”。
那么,有沒有一種方法可以將Logo.png轉換成Base64格式,比如一個簡單的函數調用:
<xsl:template match="image">
<xsl:variable name="file-path"><xsl:value-of select="@xlink:href"/></xsl:variable>
<img src="to-base64($file-path)"/>
</xsl:template>
要創建如下輸出:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA...."/>
問題#2 (pdf轉base64) 所以另一個棘手的部分是,在中間格式中,xlink:href也可以導致一個. pdf文件...
<image xlink:href="files\Table_1234.pdf"/>
如果也有可能以與上面相同的方式將其轉換為base64圖像,那就太好了。
或者也可能有另一種方法來實現HTML文檔變得“獨立”,但轉換到base64是我目前唯一的想法。
方法1 (Saxon Java擴展函數) 我嘗試按照這個文檔為Saxon 12 HE創建一個Java擴展函數
所以我實現了一個ExtensionFunctionDefinition
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.lib.ExtensionFunctionCall;
import net.sf.saxon.lib.ExtensionFunctionDefinition;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.value.SequenceType;
import net.sf.saxon.value.StringValue;
public class ImageToBase64 extends ExtensionFunctionDefinition {
@Override
public StructuredQName getFunctionQName() {
return new StructuredQName("ext", "http://example.com/saxon-extension", "imageToBase64");
}
@Override
public SequenceType[] getArgumentTypes() {
return new SequenceType[]{SequenceType.SINGLE_STRING};
}
@Override
public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) {
return SequenceType.SINGLE_STRING;
}
@Override
public ExtensionFunctionCall makeCallExpression() {
return new ExtensionFunctionCall() {
@Override
public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
var filePath = ((StringValue)arguments[0]).getStringValue();
// open file and convert to base64 string
var resultBase64 = "12345";
return StringValue.makeStringValue(resultBase64);
}
};
}
}
因為文件上說:& quot實現這些擴展功能的類必須向配置& quot這可以是& quot通過子類化net.sf.saxon.Transform或net.sf.saxon.Query來實現,覆蓋方法applyLocalOptions(),以便它對config . registerextensionfunction()進行適當的調用;"我還添加了一個擴展net.sf.saxon.Transform的類:
import net.sf.saxon.Transform;
import net.sf.saxon.trans.CommandLineOptions;
public class Configuration extends Transform {
@Override
protected void applyLocalOptions(CommandLineOptions options, net.sf.saxon.Configuration config) {
config.registerExtensionFunction(new ImageToBase64());
super.applyLocalOptions(options, config);
}
}
當我構建工件以獲取jar文件時(我使用IntelliJ btw。)我只加了& quot編譯輸出& quot所以罐子最后是3kb。
然后,我將jar放到Apache FOP的saxon-he-12.2.jar旁邊的lib文件夾中,并添加了 xmlns:ext = & quot;http://example.com/saxon-extension"到xsl:stylesheet。
但是當我現在打電話的時候
<xsl:value-of select="ext:imageToBase64('my/file/path')"/>
我得到錯誤net . SF . Saxon . trans . XPath exception:找不到名為Q { http://example . com/Saxon-extension } imageto base 64()的單參數函數
我在@MartinHonnen的幫助下完成了這項工作,他告訴我創建自己的擴展函數。
所以我創建了一個新的java程序(使用Java 8很重要)并添加了兩個類:
package ExtensionsPackage;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.lib.ExtensionFunctionCall;
import net.sf.saxon.lib.ExtensionFunctionDefinition;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.value.SequenceType;
import net.sf.saxon.value.StringValue;
public class ImageToBase64 extends ExtensionFunctionDefinition {
@Override
public StructuredQName getFunctionQName() {
return new StructuredQName("ext", "http://example.com/saxon-extension", "imageToBase64");
}
@Override
public SequenceType[] getArgumentTypes() {
return new SequenceType[]{SequenceType.SINGLE_STRING};
}
@Override
public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) {
return SequenceType.SINGLE_STRING;
}
@Override
public ExtensionFunctionCall makeCallExpression() {
return new ExtensionFunctionCall() {
@Override
public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
String filePath = ((StringValue)arguments[0]).getStringValue();
// open file and convert to base64 string
String resultBase64 = "12345";
return StringValue.makeStringValue(resultBase64);
}
};
}
}
根據這個stackoverflow-entry,另一個類MyTransformerFactory:
package ExtensionsPackage;
import net.sf.saxon.Configuration;
import net.sf.saxon.TransformerFactoryImpl;
import net.sf.saxon.lib.ExtensionFunctionDefinition;
public class MyTransformerFactory extends TransformerFactoryImpl {
public MyTransformerFactory() {
super();
ExtensionFunctionDefinition imageToBase64Function = new ImageToBase64();
this.getProcessor().registerExtensionFunction(imageToBase64Function);
}
public MyTransformerFactory(Configuration config) {
super(config);
ExtensionFunctionDefinition imageToBase64Function = new ImageToBase64();
this.getProcessor().registerExtensionFunction(imageToBase64Function);
}
}
現在構建一個jar文件,并將其放入Apache FOP的lib文件夾中。
然后添加set custom opts =-DJ avax . XML . transform . transformer factory = extensions package。我的變壓器工廠 并將%CUSTOMOPTS%添加到:runFop。
將名稱空間添加到樣式表中:
<xsl:stylesheet version="1.0"
xmlns:ext="http://example.com/saxon-extension">
像這樣使用它:
<xsl:value-of select="ext:imageToBase64('my/file/path')"/>
如果fop.bat現在通過控制臺執行,xsl:value-of將提供12345。