9

I have seen several questions on how to encode an image file in base64, but how about the other way around - how do I reconstitute a picture from a base64 string stored in an XML file?

<resource>
<data encoding="base64">
R0lGODlhEAAQAPMAMcDAwP/crv/erbigfVdLOyslHQAAAAECAwECAwECAwECAwECAwECAwECAwEC
AwECAyH/C01TT0ZGSUNFOS4wGAAAAAxtc09QTVNPRkZJQ0U5LjAHgfNAGQAh/wtNU09GRklDRTku
MBUAAAAJcEhZcwAACxMAAAsTAQCanBgAIf8LTVNPRkZJQ0U5LjATAAAAB3RJTUUH1AkWBTYSQXe8
fQAh+QQBAAAAACwAAAAAEAAQAAADSQhgpv7OlDGYstCIMqsZAXYJJEdRQRWRrHk2I9t28CLfX63d
ZEXovJ7htwr6dIQB7/hgJGXMzFApOBYgl6n1il0Mv5xuhBEGJAAAOw==
</data>
<mime>image/gif</mime>
<resource-attributes>
    <file-name>clip_image001.gif</file-name>
</resource-attributes>
</resource>

Given the above XML node resource, how do I go about creating clip_image001.gif?

Please suggest:

  1. XSLT processors and/or extensions enable this, plus
  2. a sample XSLT that triggers the conversion

Note that it must be able to handle at least GIF & PNG file formats. Preferably not restricted to any OS.


Implemented solution

Based around Mads Hansen's solution. Main difference being that I referenced net.sf.saxon.value.Base64BinaryValue directly in my namespace rather than using the saxon namespace, because I understood the Java APIs more intuitively than the Saxonica website's descriptions of the base64Binary-to-octets and base64Binary functions.

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:b64="net.sf.saxon.value.Base64BinaryValue"
    xmlns:fos="java.io.FileOutputStream"
    ...
    exclude-result-prefixes="b64 fos">
...
<xsl:for-each select="resource">                
    <xsl:variable name="b64" select="b64:new(string(data))"/>
    ...
    <xsl:variable name="fos" select="fos:new(string($img))"/>
    <xsl:value-of select="fos:write($fos, b64:getBinaryValue($b64))"/>  
    <xsl:value-of select="fos:close($fos)"/>
</xsl:for-each>
...

P.S. See sibling question for my implementation of how to obtain the hashes necessary to identify the image files.


This question is a subquestion of another question I have asked previously.
Community
  • 1
  • 1
bguiz
  • 27,371
  • 47
  • 154
  • 243

4 Answers4

10

I found this entry from the XSL maiing lists that describes how to use the Saxon extension function xs:base64Binary-to-octet to stream it out to a file using the Java FileOutputStream in an XSLT 2.0 stylesheet:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema";
xmlns:saxon="http://saxon.sf.net/";
xmlns:fos="java.io.FileOutputStream">
<xsl:template match="/">
   <xsl:variable name="img" select="concat('c:\test\jesper', '.jpg')"/>
   <xsl:variable name="fos" select="fos:new(string($img))"/>
   <xsl:value-of select="fos:write($fos,
saxon:base64Binary-to-octets(xs:base64Binary(my-base64-encoded-image)))"/>
   <xsl:value-of select="fos:close($fos)"/>
</xsl:template>
</xsl:stylesheet>
Mads Hansen
  • 63,927
  • 12
  • 112
  • 147
  • Thank you! This is what I wanted, cos it's actually writing the images to external files. – bguiz Nov 07 '09 at 10:51
  • I think it should be `saxon:base64Binary-to-octets` (with the trailing `s`). See http://www.saxonica.com/documentation/extensions/functions.html – Jukka Matilainen Nov 07 '09 at 20:53
  • Error: Prefix must resolve to a namespace: xs, on line xs:base64Binary(my-base64-encoded-image), **more** Extension function http://saxon.sf.net/ : base64Binary-to-octets is unknown – Sarz May 02 '16 at 08:09
  • @Sarz I believe that is a premium feature and you either need the PE or EE version. http://www.saxonica.com/html/documentation/functions/saxon/base64Binary-to-octets.html – Mads Hansen May 02 '16 at 12:28
7

The following works:

<img>
  <xsl:attribute name="src">
    <xsl:value-of select="concat('data:image/gif;base64,',xPath)"/>
  </xsl:attribute>
</img>
Community
  • 1
  • 1
StrangeDays
  • 352
  • 5
  • 4
  • +1 @StrangeDays : Thanks for your answer! I'm not going to look into this (was a long time ago) anytime soon, but if it does indeed work, it does look like a much more neat & elegant solution than the other ones suggested here so far. – bguiz Nov 18 '10 at 05:54
  • forgot a space there: – Steven Dec 03 '12 at 08:02
  • This is to generate HTML IMG element with BASE64 source. Not exactly an answer to the question. – Pavel Horal Mar 23 '14 at 09:05
1

Transform it to HTML.

<img src="data:{mime};base64,{data}" />
ChaosPandion
  • 77,506
  • 18
  • 119
  • 157
  • What XSLT processor and extensions do you use? – bguiz Nov 06 '09 at 03:15
  • And I want to be able to actually generate the image files, that is create clip_image001.gif, and then in the output html get , because I need to generate a hash from the picture file as well. – bguiz Nov 06 '09 at 06:56
0

There is a better method available since Saxon 9.5 via the EXPath File extension module (available in Saxon-PE and Saxon-EE).

Here is a fragment of the code I'm using to extract binary image files from Word documents (source XML is in WordProcessingML format):

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:file="http://expath.org/ns/file" xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage">

<xsl:template match="/pkg:package">
    <xsl:apply-templates select="pkg:part/pkg:binaryData"/>
</xsl:template>

<xsl:template match="pkg:binaryData">
    <xsl:variable name="filename">
        <xsl:value-of select="replace(../@pkg:name, '/word/media/', '')"/>
    </xsl:variable>
    <xsl:variable name="path" select="concat('/some/folder/', $filename)"/>
    <xsl:message><xsl:value-of select="$path"/></xsl:message>

    <xsl:value-of select="file:write-binary($path, xs:base64Binary(string()))"/>       
</xsl:template>
ju1ce--
  • 151
  • 6