Scribus XML using Scripter

From Scribus Wiki
Revision as of 04:29, 30 November 2013 by Gpittman (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
 Hourglass1.png This feature/option is considered experimental
This article is part of the Scripts series.

One of the issues that very quickly was noticeable with using a modified SLA file as in Scribus files as XML was the realization that PAGEOBJECTS in an SLA file are appended at the end of the file as they are created. There is an attribute, OwnPage, that tells which page the object is placed on. Even though there might be a trend to add objects in sequence with the pages, it isn't unusual sometime near the end of the layout process to add something up front. This can be overcome (most likely), but requires a lot more logic in the XSL file.

Scripter, of course has a LOT of access to document and object information, thus this idea was born. You might also be interested in Scribus xhtml using Scripter.

export2xml.py

This is a work-in-progress, so expect it to change as new features are added.

EDIT 2013-11-4: I have now incorporated position attributes, but not using them yet in the XSL below.

#!/usr/bin/env python
# File: export2xml.py - Extracts the content from a document, saving to an xml file
# 2013.10.29 Gregory Pittman
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
 
import scribus
 
 
def exportText(textfile):
    page = 1
    pagenum = scribus.pageCount()
    T = []
    content = []
    T.append('<?xml version="1.0" encoding="UTF-8"?>\n')
    T.append('<?xml-stylesheet type="text/xsl" href="scribus.xsl"?>\n')
    T.append('<document>\n')
    T.append('<version>Scribus ' + str(scribus.scribus_version_info[0]) + '.' + str(scribus.scribus_version_info[1]) + '.' + str(scribus.scribus_version_info[2]) + str(scribus.scribus_version_info[3]) + '</version>\n')
    while (page <= pagenum):
        scribus.gotoPage(page)
        pagesize = scribus.getPageSize()
        d = scribus.getPageItems()
        strpage = str(page)
        T.append('<page number="'+ strpage + '">\n')
        for item in d:
            Xpos, Ypos = scribus.getPosition(item[0])
            Xpos = str(int(Xpos))
            Ypos = str(int(Ypos))
            if (item[1] == 4):
                filtered = '<para>'
                contents = scribus.getAllText(item[0])
                if (contents in content):
                    contents = ''
                else:
                    for char in contents:
                        if (ord(char) == 28):
                            char = ' '
                        elif (ord(char) == 27):
                            char = chr(10)
                        elif (ord(char) == 38):
                            char = '&amp;'
                        elif ((ord(char) == 13) or (ord(char) == 10)):
                            char = "</para><para>"
                        filtered = filtered + char
                    contents = filtered
                T.append('<object type="text" Xpos="' + Xpos +'" Ypos ="' + Ypos + '" >' + contents + '</para>\n')
                T.append('</object>\n')
                content.append(contents)
            elif (item[1] == 2):
                imgname = scribus.getImageFile(item[0])
                imgsize = scribus.getSize(item[0])
                picwidth = int(700 * imgsize[0]/pagesize[0])
                T.append('<object type="image" width="' + str(picwidth) + 'px" source="' + imgname + '" Xpos="' + Xpos +'" Ypos ="' + Ypos + '" >' + imgname + '</object>\n')
 
        T.append('</page>\n')
        page += 1
    T.append('</document>\n')
    output_file = open(textfile,'w')
    output_file.writelines(T)
    output_file.close()
    endmessage = textfile + ' was created'
    scribus.messageBox("Finished", endmessage,icon=0,button1=1)
 
 
if scribus.haveDoc():
    textfile = scribus.fileDialog('Enter name of file to save to', \
                                  filter='Text Files (*.xml);;All Files (*)')
    try:
        if textfile == '':
            raise Exception
        exportText(textfile)
    except Exception, e:
        print e
 
else:
    scribus.messageBox('Export Error', 'You need a Document open, and a frame selected.', \
                       icon=0, button1=1)

And here is an example of the XML you get from this:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="scribus.xsl"?>
<document>
<version>Scribus 1.4.3</version>
<page number="1">
<object type="image" width="426px" source="/home/gregp/.scribus/scrapbook/main/Image1/galapagos1.jpeg" Xpos="51" Ypos ="67" >/home/gregp/.scribus/scrapbook/main/Image1/galapagos1.jpeg
</object>
<object type="image" width="408px" source="/home/gregp/.scribus/scrapbook/main/Image2/galapagos2.jpeg" Xpos="214" Ypos ="510" >/home/gregp/.scribus/scrapbook/main/Image2/galapagos2.jpeg
</object>
<object type="text" Xpos="49" Ypos ="327" ><para>3 May. Bistritz.--Left Munich at 8:35 P.M., on 1st May, arriving at Vienna early next morning; should have arrived at 6:46, but train was an hour late. Buda-Pesth seems a wonderful place, from the glimpse which I got of it from the train and the little I could walk through the streets. I feared to go very far from the station, as we had arrived late and would start as near the correct time as possible.</para><para>I found my smattering of German very useful here, indeed, I don't know how I should be able to get on without it.</para>
</object>
</page>
<page number="2">
<object type="image" width="370px" source="/home/gregp/.scribus/scrapbook/main/Image4/galapagos3.jpeg" Xpos="46" Ypos ="44" >/home/gregp/.scribus/scrapbook/main/Image4/galapagos3.jpeg
</object>
</page>
</document>

The starting point was to generate pseudopages (this is all just one big webpage) by using the table tags to map out a space. By using page dimensions, a proportionally-sized area could be made based on an arbitrary width of 900px, with the plan to have additional tables inside for objects.

Some initial issues

Similar to the overall object-ordering problem in a SLA file, each page numbers frames as you add them, so as you make a list of page objects, this order is created, but this is at least a smaller problem than ordering objects from many different pages. My plan is to use the getPosition data on objects to then sort them – after that, the trick is to use some positioning method. Presently, I still haven't decided whether to use CSS or some other method to try to semi-accurately position objects on the table page space.

In contrast to using an SLA file, the output from Scripter with text frames may not be XML-compliant. For example, the '&' character comes out as that character. The answer is to send it to XML as &amp; instead. I suspect I will discover other characters that need similar treatment.

Another issue is tabs, which come out as a Ctrl-something-inscrutable character. So far, I have simply deleted these.

Next is the issue with CR/nextline characters, which come out as ASCII 10 or 13. Taking a cue from the SLA files, I instead create a para tag to handle this, to create p tags.

At this point, the script works, but only handles text and image frames. No usage of style information is present, as of yet. It does work with both Scribus 1.4.3 and 1.5.0svn.

scribus.xsl

This is not the same as the one used to convert the modified SLA/XML files, so watch the naming not only here, but also in the script above, and change as needed. Note that the background of the webpage is a grey, while the background of the document "pages" is white.

<?xml version="1.0" encoding="utf-8"?>
 
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
 
    <html>
    <body bgcolor="#eeeeee">
      <xsl:for-each select="document">
	<h3>This document was created using <xsl:value-of select="version" /></h3>
	<xsl:for-each select="page">
	  <table border="1" cellspacing="0" bgcolor="ffffff">
	    <tr><td width="900px" height="1160px" valign="top">
	  <p><strong>Page <xsl:value-of select="@number" /></strong></p>
	  <xsl:for-each select="object">
	    <xsl:if test="(@type='text')">
	      <table border="0">
		<tr><td width="20px"></td><td>
		<xsl:for-each select="para">
		  <p><xsl:value-of select="." /></p>
		</xsl:for-each></td></tr>
	      </table>
	    </xsl:if>
	    <xsl:if test="@type='image'">
	      <table border="0" style="position: relative; left: 150;">
		<tr><td width="20px"></td><td><img src="{@source}" width="{@width}" /></td></tr>
	      </table>
	    </xsl:if>
	  </xsl:for-each>
	  </td></tr>
	</table>
	</xsl:for-each>
      </xsl:for-each>
    </body>
    </html>
  </xsl:template>
</xsl:stylesheet>