odf uof_开放式输出:从Web服务生成ODF电子表格

odf uof

每当网页或服务提供数据时,用户特别喜欢以电子表格格式或至少以他们可以轻松加载到电子表格中的格式来获取数据。 本文说明如何通过直接按字节创建文件(需要研究ODS文件的内部结构)或通过简化工作的特定库来生成开放文档格式(ODF)电子表格文件(或ODS)。 您还可以一目了然地生成CSV文件-不仅因为它们是一种“最低公分母”交换格式,而且还因为您可以将它们自动转换为ODS文件。

在你开始前

首先获取一些数据。 我使用了一个简单的数据库(请参见清单1 ),其中包括世界上的国家,地区和城市-大约300万条记录。 我从免费的全球城市表开始(请参阅参考资料中的链接),并添加了ISO 3166国家代码表以及ISO 3166-2和FIPS 10-4地区代码表,因为以前的代码(而不是后者中使用的更标准的代码)。 我添加了completeCities视图只是为了简化代码示例。 基本上,请了解:

  • 国家用代码标识(例如,乌拉圭为UY )并有名称。
  • 国家/ 地区具有通过代码(国家/ 地区唯一)标识并带有名称的区域。
  • 城市位于一个国家/地区中,并具有名称(有两种版本:普通的,不带重音的ASCII名称和外来字符名称),人口(如果知道)和地理坐标。
清单1.创建将要查询的视图
CREATE DATABASE world
  DEFAULT CHARACTER SET utf8
  COLLATE utf8_general_ci;

USE world;

CREATE TABLE countries (
  countryCode char(2) NOT NULL,
  countryName varchar(50) NOT NULL,
  PRIMARY KEY (countryCode),
  KEY countryName (countryName)
);

CREATE TABLE regions (
  countryCode char(2) NOT NULL,
  regionCode char(2) NOT NULL,
  regionName varchar(50) NOT NULL,
  PRIMARY KEY (countryCode,regionCode),
  KEY regionName (regionName)
);

CREATE TABLE cities (
  countryCode char(2) NOT NULL,
  cityName varchar(50) NOT NULL,
  cityAccentedName varchar(50) NOT NULL,
  regionCode char(2) NOT NULL,
  population bigint(20) NOT NULL,
  latitude float(10,7) NOT NULL,
  longitude float(10,7) NOT NULL,
  KEY `INDEX` (countryCode,regionCode,cityName),
  KEY cityName (cityName),
  KEY cityAccentedName (cityAccentedName)
);

CREATE VIEW completeCities AS
  SELECT
    co.countryCode AS countryCode,
    co.countryName AS countryName,
    re.regionCode AS regionCode,
    re.regionName AS regionName,
    ci.cityName AS cityName,
    ci.population AS population,
    ci.latitude AS latitude,
    ci.longitude AS longitude
  FROM cities ci
    JOIN regions re ON re.countryCode=ci.countryCode
        AND re.regionCode=ci.regionCode
    JOIN countries co ON co.countryCode=re.countryCode
  ORDER BY 2,4,5;

我还设置了一个简单的页面来测试服务。 该页面允许您输入字符串,服务将获取名称以该字符串开头的所有城市的数据(通过运行SELECT * FROM completeCities WHERE cityName LIKE '...%' )。 该页面(请参见图1 )非常简单:您只需要一个字符串文本框和每个服务按钮即可。

图1.一个简单的页面,允许您调用不同的服务
页面以标有“城市名称开始”的文本字段开头。通过该字段下方的按钮可通过以下方式获取它:PHP生成的CSV,PHP生成的CSV变体,Python生成的CSV,等等。

单击任何按钮都将调用相应的服务,该服务将生成CSV或ODS文件(请参见图2 )。 为了安全起见,并确保不存在不兼容性,我尝试使用KOffice KSpread和OpenOffice.org Calc打开所有生成的文件。

图2.所有按钮产生相同的结果,但方式不同
图1中的上一个屏幕位于背景中。单击页面上的一个按钮,然后弹出窗口覆盖屏幕。该窗口的标题为“正在打开xml_1_php.ods”。用户可以取消或单击“确定”。

产生CSV档案

首先生成简单的CSV文件。 CSV文件通常被各种软件接受,并且可以自动发送到ODS文件中(尽管在安装上有些不便)。

使用PHP生产CSV文件非常容易(请参见清单2中的代码)。 获得所需数据后,只需遍历结果并一次打印一个字段即可。 我将SELECT输出限制为1,000条记录,但我本来可以增加到65,536,这是OpenOffice.org Calc(和巧合的是Microsoft®OfficeExcel®)的最大行数,或KOffice KSpread的最大行数(32,767)。 请注意,需要使用addslashes()来转义字段值; 否则,带引号的值会破坏代码。

清单2. Csv_1.php生成一个简单的CSV文件
// Get the data:

$start= addslashes($_REQUEST["start"]);
$conn= mysql_connect("localhost", "testuser", "testpass");
$db= mysql_select_db("world");
$cur= mysql_query("SELECT * FROM completeCities ".
    "WHERE cityName LIKE '{$start}%' LIMIT 1000");

// Send out the data, with headers identifying it as CSV:

header("Content-type: text/csv");
header("Content-Disposition: attachment; filename=csv_1.csv");

while ($row= mysql_fetch_assoc($cur)) {
    $sep= "";
    foreach ($row as $value) {
        $item= is_numeric($value) ? $value : '"'.addslashes($value).'"';
        echo $sep.$item;
        $sep= ',';
    }
    echo "\n";
}

您可以通过使用fputcsv()来更优雅地对主循环进行fputcsv() ,它可以处理格式问题(请参见清单3 )。 如果多个用户同时调用Web脚本,则使用tmpfile()可以避免冲突。 文件准备好后,将发送与清单2相同的标头,然后您需要读入临时文件的内容并进行打印。

清单3.变体(csv_2.php)使用fputcsv,这是PHP的CSV函数之一
// ...generate results...

$handle= tmpfile();
while ($row= mysql_fetch_assoc($cur)) {
    fputcsv($handle, $row);
}

// ...put out headers...

fseek($handle,0);
while ($contents= fread($handle, 1024)) {
    print $contents;
}

// ...clean up code...

Python的csv模块使事情变得更加容易,如清单4所示。 获取数据的方法与PHP相似。 创建CSV文件需要定义要使用的定界符(逗号[ , ])以及要引用的字段; 我选择引用所有非数字字段。 使用TemporaryFile保存清理代码; 在Python 2.6版中, SpooledTemporaryFile会更好,因为除非文件太大,否则数据会保留在内存中。 csv.writer方法从可迭代对象生成CSV文件。 cursor.fetchall()有点像野兽,四行足以产生CSV输出。 然后,就像以前PHP版本一样,您仅需要输出标头,然后是临时文件中的数据本身。

清单4. Csv_3.py
def index(req):
    # ...imports...

    # Get the data:

    start= req.form["start"]
    conn= MySQLdb.connect(host= "localhost", user= "testuser",
        passwd= "testpass", db= "world")
    cursor= conn.cursor()
    cursor.execute("""SELECT * FROM completeCities WHERE
        cityName LIKE %s LIMIT 1000""", start+"%")

    #   Create the CSV file:

    csv.register_dialect("simple", delimiter= ',', quoting= csv.QUOTE_NONNUMERIC)
    myFile= tempfile.TemporaryFile()
    obj= csv.writer(myFile, dialect= "simple")
    obj.writerows(cursor.fetchall())

    # ...clean up...

    # Send back the data, with headers identifying the data as CSV:

    req.headers_out.add("Content-type", "text/csv");
    req.headers_out.add("Content-Disposition",
        "attachment;filename=csv_3.csv");
    myFile.seek(0)
    return myFile.read()

ODS文件是什么样的?

ODF文件实际上是ZIP文件,其中包含大量文件和目录。 并非所有内容都是强制性的; 例如,我使用KOffice KSpread和OpenOffice.org Calc创建了简单的电子表格(在A1单元中只有IBM ),然后提取了生成的ODS文件以查看其中包含的内容。 清单5显示了结果。

清单5.检查ODS文件的内容
# unzip -l kspread_ibm.ods
Archive:  kspread_ibm.ods
  Length     Date   Time    Name
 --------    ----   ----    ----
       46  08-21-09 14:00   mimetype
     2092  08-21-09 14:00   content.xml
     2631  08-21-09 14:00   styles.xml
     6342  08-21-09 14:00   settings.xml
      634  08-21-09 14:00   meta.xml
     1171  08-21-09 14:00   Thumbnails/thumbnail.png
      786  08-21-09 14:00   META-INF/manifest.xml
 --------                   -------
    13702                   7 files

# unzip -l openoffice_ibm.ods
Archive:  openoffice_ibm.ods
  Length     Date   Time    Name
 --------    ----   ----    ----
       46  08-21-09 17:00   mimetype
        0  08-21-09 17:00   Configurations2/statusbar/
        0  08-21-09 17:00   Configurations2/accelerator/current.xml
        0  08-21-09 17:00   Configurations2/floater/
        0  08-21-09 17:00   Configurations2/popupmenu/
        0  08-21-09 17:00   Configurations2/progressbar/
        0  08-21-09 17:00   Configurations2/menubar/
        0  08-21-09 17:00   Configurations2/toolbar/
        0  08-21-09 17:00   Configurations2/images/Bitmaps/
     3808  08-21-09 17:00   content.xml
     6411  08-21-09 17:00   styles.xml
      876  08-21-09 17:00   meta.xml
     1012  08-21-09 17:00   Thumbnails/thumbnail.png
     7226  08-21-09 17:00   settings.xml
     1896  08-21-09 17:00   META-INF/manifest.xml
 --------                   -------
    21275                   15 files

在这两种情况下,第一个包含的文件都是mimetype,其中包含application/vnd.oasis.opendocument.spreadsheet 。 该文件必须是软件包ZIP文件的第一个流。

另一个常见文件是thumbnail.png:ODF文件出于演示目的,包含保存文档的128 x 128缩略图。 但是,规范并未强制要求包含该映像,因此出于本示例的目的,您可以跳过该步骤。

同样,您可以删除大多数其他文件,但是必须在manifest.xml文件中包含META-INF目录,该文件描述了ZIP中包含的所有其他文件,而content.xml文件中存储了ZIP文件。实际的电子表格内容。 进行了一些实验,确认KOffice KSpread和OpenOffice.org Calc都可以处理这么小的内容,因此我只需要创建三个文件:

  • mimetype文件是常量,因此生成它很简单。
  • 对于减少的内容集,manifest.xml文件只有几行长,如清单6所示。
  • 更复杂的文件是contents.xml。
清单6.一个简约的manifest.xml文件
<?xml version='1.0' encoding='UTF-8'?>
<manifest:manifest>
 <manifest:file-entry
   manifest:media-type='application/vnd.oasis.opendocument.spreadsheet'
   manifest:full-path='/' />
 <manifest:file-entry
   manifest:media-type='text/xml'
   manifest:full-path='content.xml' />
</manifest:manifest>

基本上,XML内容文档包含一个office:spreadsheet元素,该元素本身包含一个table:table元素,代表电子表格中的每个工作表。 该元素本身包括table:table-row元素(每行一个),其中table:table-cell元素用于该行中的顺序单元格,如清单7所示。

清单7.仅包含一个单元格的样本内容文件
<?xml version="1.0" encoding="UTF-8"?>
<office:document-content ...many snipped attributes...>
<office:automatic-styles />
  <office:body>
    <office:spreadsheet>
      <table:table table:name="the sheet name">
        <table:table-row>
          <table:table-cell>
            <text:p>IBM</text:p>
          </table:table-cell>
        </table:table-row>
      </table:table>
    </office:spreadsheet>
  </office:body>
</office:document-content>

请注意,这种简约的内容文件不允许使用任何样式,但是稍后会介绍。 让我们开始生成实际的ODS文件。

通过XML直接生成ODS文件

因为XML文件是文本文件,并且可以通过命令行轻松地对其进行压缩,所以使用任何脚本语言生成ODS文件都是很简单的。 本文提供了两种方法:使用PHP的简单方法和使用适当模块的Python的更复杂方法。 (如果您想做更完善的工作,则有几个用于PHP的XML和ZIP软件包。)让我们从清单8所示的简单版本开始。 获取数据后(与以前的清单相同),您必须创建contents.xml文件; 首先包含一个常量标题,然后是结果数据,一行一行,一个单元格,最后一个页脚。 manifest.xml和mimetype文件可以通过使用file_put_contents()轻松生成。 然后,压缩所有文件,将生成的ZIP文件的内容放在适当的头文件之前,并删除所有多余的文件和目录以进行清理。

清单8. Xml_1.php
// ...get the data...

/*
    Define the constants that will be needed for the text files
  (The constants were somewhat abridged; see the original source code.)
*/

define(MIMETYPE, "application/vnd.oasis.opendocument.spreadsheet");

define(XML_MANIFEST,
    "<?xml version='1.0' encoding='UTF-8'?>\n".
    "<manifest:manifest> ... </manifest:manifest>");

define(XML_START,
    "<?xml version='1.0' encoding='UTF-8'?> ... ".
    "<office:body><office:spreadsheet><table:table table:name='Results'>");

define(XML_ROW_START, "<table:table-row>");

define(XML_CELL_START, "<table:table-cell><text:p>");

define(XML_CELL_END, "</text:p></table:table-cell>");

define(XML_ROW_END, "</table:table-row>");

define(XML_END,
    "</table:table></office:spreadsheet></office:body></office:document-content>");

// Create the content.xml file:

$contents= XML_START;
while ($row= mysql_fetch_assoc($cur)) {
    $contents.= XML_ROW_START;
    foreach ($row as $value) {
        $contents.= XML_CELL_START;
        $contents.= htmlentities($value);
        $contents.= XML_CELL_END;
    }
    $contents.= XML_ROW_END;
}
$contents.= XML_END;

// let $tempzip be the name of a temporary file

mkdir($tempzip);
mkdir($tempzip."/META-INF");
file_put_contents($tempzip."/META-INF/manifest.xml", XML_MANIFEST);
file_put_contents($tempzip."/content.xml", $contents);
file_put_contents($tempzip."/mimetype", MIMETYPE);
system("cd {$tempzip}; zip -mr {$tempzip} mimetype META-INF/* content.xml >/dev/null");

// Put out the data:

header("Content-Type: application/vnd.oasis.opendocument.spreadsheet");
header("Content-Disposition: attachment; filename=xml_1.ods");
header("Content-Transfer-Encoding: binary");
readfile($tempzip.".zip");

// ...clean up, using unlink() and rmdir() to delete all created files

现在,让我们转向Python,通过在内存中创建XML对象,将它们转储到文件中,然后使用zip模块生成所需的ODS文件,来获得一个更加“模块化”的版本,如清单9所示。 获取数据与清单4相同。 manifestXml对象可以用几行代码创建,因为它的内容是固定的。 建立contentXml对象比较contentXml ,因为它是一个更大,更复杂的结构。 请注意,您需要为每个游标行执行一个循环(在XML对象中创建一行),然后再次为每个数据字段执行一个循环(向先前创建的每个行中添加单元格)。 一切准备就绪后,只需编写实际文件,使用zip创建所需的ZIP文件,然后通过输出输出标头以及压缩结构的内容来完成。

清单9. Xml_2.py
def index(req):
    # ...imports...
    # ...get the data...
    # ...create the manifestXml object...

    # Create the contentXml document:

    contentXml= getDOMImplementation().createDocument("office",
        "office:document-content", None)
    contentXml.documentElement.setAttribute("office:version", "1.1")
    contentXml.documentElement.setAttribute("xmlns:table",
        "urn:oasis:names:tc:opendocument:xmlns:table:1.0")

    # ...add more attributes to the contentXml object...
    # ...add an empty "office:automatic-styles" element to the document...

    obd= contentXml.createElement("office:body")
    contentXml.documentElement.appendChild(obd)

    oss= contentXml.createElement("office:spreadsheet")
    obd.appendChild(oss)

    table= contentXml.createElement("table:table")
    table.setAttribute("table:name", "Results")
    oss.appendChild(table)

    # Each cursor row becomes a row in the table; each field, a cell:

    for datarow in cursor.fetchall():
        tablerow= contentXml.createElement("table:table-row")
        table.appendChild(tablerow)
        for datafield in datarow:
            cell= contentXml.createElement("table:table-cell")
            tablerow.appendChild(cell)
            text= contentXml.createElement("text:p")
            cell.appendChild(text)
            text.appendChild(contentXml.createTextNode(str(datafield)))

    # Create all required directories and files:

    tempDir= tempfile.mkdtemp("", "xmlpy")
    os.mkdir(tempDir+"/META-INF")

    contentFile= open(tempDir+"/content.xml", "w")
    contentFile.write(contentXml.toxml())
    contentFile.close()

    # ...create files "mimetype" and "META-INF/manifest.xml" similarly...

    # Zip everything:

    myZip= zipfile.ZipFile(tempDir+".zip", "w")
    os.chdir(tempDir)
    myZip.write("mimetype")
    myZip.write("META-INF/manifest.xml")
    myZip.write("content.xml")
    myZip.close()

    # ...read the contents of the created zip file into variable dataToReturn
    # ...clean up, by using os.remove() and os.rmdir()
    # ...send back dataToReturn, with appropriate headers

代码很冗长,您可以像使用PHP一样进行操作,但是我想展示解决同一问题的不同方法。 下一节将介绍一些可以进一步减少编码的库。

通过特定的库生产ODS

手动创建XML文件很有趣,但是幸运的是,有些库可以直接生成ODS文档。 我使用了ods-php,即使在0.1版(以及该版本的候选发行版)中,它也能完成工作。 (您也可以使用此类读取 ODF文件。)不利的一面是,除了PHP代码本身之外,没有任何文档,因此使此库正常工作需要进行一些猜测。

获取数据与之前相同。 产生ODS文件需要创建一个newOds()对象,并使用addCell方法addCell添加单元格。 单元格从行和列开始,从0开始; 单元格A1将是第0行第0列。准备好对象后, saveOds方法将其以正确的ODS格式保存到磁盘,剩下的就是放出适当的头文件,然后是ODS文件内容,如清单1所示。 10 。 清理需要删除您刚刚创建的ODS文件。

清单10. Ods_1.php
// ...get the data...

// Create an ODS object and load data into it:

$object= newOds();
for ($curRow=0; $row= mysql_fetch_assoc($cur); $curRow++) {
    $curCol= 0;
    foreach ($row as $value) {
        $type= is_numeric($value) ? "float" : "string";
        $object->addCell(0, $curRow, $curCol, $value, $type);
        $curCol++;
    }
}

// Write the object to a temporary file:

$tempname= tempnam("./", "odsphp");
unlink($tempname);
$tempname.= ".ods";
saveOds($object, $tempname);

// ...send out the contents of the $tempname file, with appropriate headers...
// ...clean up...

Python的Odfpy模块提供了一个类似但内容更多的库。 您可以从头开始构建各种ODF文件,也​​可以将现有文档加载到内存中,进行更改,然后再次保存。 在获取数据后(以与以前类似的方式),要创建ODS文件,必须使用OpenDocumentSpreadsheet()创建文档。 然后,创建表并向其中添加表,最后,通过首先向表中添加行,然后向行中添加单元格来插入数据,如清单11所示。 现在,应该已经熟悉了代码的最后一部分:放出标题,获取并放出所产生的ODS文件的内容,并通过删除多余的文件进行清理。

清单11. Ods_2.py
def index(req):
    # ...imports...

    # ...get the data...

    # Build the ODS object, row by row and cell by cell:

    doc= OpenDocumentSpreadsheet()
    table= Table(name="Results")

    for cursorRow in cursor.fetchall():
        tr= TableRow()
        table.addElement(tr)
        for val in cursorRow:
                tc= TableCell()
                tc.addElement(P(text=val))
                tr.addElement(tc)

    doc.spreadsheet.addElement(table)
    myFile= tempfile.TemporaryFile()
    doc.write(myFile)

    # ...clean up...

    # ...send back the contents of myFile...
    # ...with headers identifying the data as ODS...

检查odfpy软件包以获取更多选项。 具体来说,您可能对xml2odf脚本感兴趣,该脚本可以帮助生成最终的ODS文件。 现在,让我们开始考虑对ODS文件进行一些修饰,以使外观更具吸引力。

爵士乐

到目前为止,您已经成功地以几种不同的方式创建了ODS文件,但是从某种程度上来说,结果是简单的(请参见图3 )。 因此,让我们研究一下在输出中包括样式文本的两种方法:一种简单的方法,即直接在PHP中生成适当的XML文件,另一种是使用Python中的Odfpy库的更为复杂的方法。

图3.到目前为止的结果
一个简单的电子表格,列出结果。

使用样式并不是很复杂,但是有很多事情要考虑。 在这种情况下,我希望标题使用大胆,蓝色的样式,在列标题中使用大胆​​的灰色样式。 我决定使用更易于使用的自动样式。 只要您手动将格式应用于任何单元格,这些样式就会自动创建(因此而得名),这些样式会包含在content.xml文件中,而不是单独包含在其中。 文档的office:automatic-styles元素应类似于清单12

清单12.为一个混乱的电子表格生产一些额外的XML
<office:automatic-styles>.
    <style:style
        style:name='bbb'
        style:family='table-cell'>.
        <style:text-properties
            fo:font-weight='bold'
            fo:color='#0000ff'
            fo:font-size='15'/>
    </style:style>

    <style:style
        style:name='bld'
        style:family='table-cell'>
        <style:text-properties
            fo:font-weight='bold'/>
        <style:table-cell-properties
            fo:background-color='#AEAEAE'/>
    </style:style>
</office:automatic-styles>

该代码在PHP中工作,与清单10几乎相同,但是您必须更改XML文档标题以包括所需的自动样式元素。 请注意,我还定义了两个新的单元格前缀,每个都包含一个适当的table:style-name属性。 最后,只需添加新的主标题,一个空白行用于间隔以及一行包含列标题,如清单13所示。

清单13. Xml_3.php
// ...everything is the same, just up to XML_START:

define(XML_AUTOMATIC_STYLES,
    "<office:automatic-styles>".
        "<style:style style:name='bbb' style:display-name='bbb' ".
            "style:family='table-cell'>".
            "<style:text-properties fo:font-weight='bold' ".
            "fo:color='#0000ff' fo:font-size='15'/>".
        "</style:style>".
        "<style:style style:name='bld'  style:display-name='bld' ".
            "style:family='table-cell'>".
            "<style:text-properties fo:font-weight='bold'/>".
            "<style:table-cell-properties fo:background-color='#AEAEAE'/>".
        "</style:style>".
    "</office:automatic-styles>");

define(XML_START,
    "<?xml version='1.0' encoding='UTF-8'?>\n".
    "<office:document-content ".
        //...many lines...
        "office:version='1.1'>".
        XML_AUTOMATIC_STYLES.
    "<office:body>".
    "<office:spreadsheet>".
    "<table:table table:name='Results'>");

// ...more define() lines, as earlier, and two new definitions:

define(XML_BBB_CELL_START,
    "<table:table-cell table:style-name='bbb'><text:p>");

define(XML_BLD_CELL_START,
    "<table:table-cell table:style-name='bld'><text:p>");

// ...then, everything the same, up to:

$contents= XML_START;

// Add a big, bold, blue, title, and an empty line:

$contents.= XML_ROW_START;
$contents.= XML_BBB_CELL_START;
$contents.= "Cities whose name starts with '".$start."'";
$contents.= XML_CELL_END;
$contents.= XML_ROW_END;

$contents.= XML_ROW_START;
$contents.= XML_ROW_END;

// Add some titles, in bold:

$contents.= XML_ROW_START;
foreach (array("Country","","Region","","City","Pop","Lat","Long") as $title) {
    $contents.= XML_BLD_CELL_START;
    $contents.= $title;
    $contents.= XML_CELL_END;
}
$contents.= XML_ROW_END;

// ...everything is the same to the end

转向Python,用odfpy创建样式并不难,但是由于文档没有那么有用,因此我不得不进行几次实验,并将获得的结果与OpenOffice.org Calc文档的内容进行比较。 您需要创建新样式并将其添加到文档的automaticstyles样式部分。 鉴于此,添加标题或列标题很容易:您只需创建一个单元格,指定所需的stylename而无需其他操作(参见清单14 )。 请注意,其余代码与清单11大致相同。

清单14. Ods_3.py
def index(req)
    # ...everything the same as in ods_a.py, up to including these lines:

    doc= OpenDocumentSpreadsheet()
    table= Table(name="Results")

    # Define a "bold big blue" style, and a simple bold on grey one:

    bbb= Style(name="bbb", family="table-cell")
    bbb.addElement(TextProperties(fontweight="bold", fontsize="13", color="#0000ff"))
    doc.automaticstyles.addElement(bbb)

    bld= Style(name="bld", family="table-cell")
    bld.addElement(TextProperties(fontweight="bold"))
    bld.addElement(TableCellProperties(backgroundcolor="#AEAEAE"))
    doc.automaticstyles.addElement(bld)

    # Add a listing description, in the bold big blue style, and skip a row:

    tr= TableRow()
    table.addElement(tr)
    tc= TableCell(stylename="bbb")
    tc.addElement(P(text="Cities whose name starts with '"+start+"'"))
    tr.addElement(tc)

    table.addElement(TableRow())

    # Add some column titles, in the simple bold style:

    tr= TableRow()
    table.addElement(tr)
    for myText in ["Country", "", "Region", "", "City", "Pop", "Lat", "Long"]:
        tc= TableCell(stylename="bld")
        tc.addElement(P(text=myText))
        tr.addElement(tc)

    # ...add the data, create the ODS, clean up; everything the same from here onwards

造型的结果,虽然可能不太值得造型奖,但至少看起来更好! 参见图4

图4.添加标题和某些样式可以增强结果。
更时尚的结果,标题为蓝色,标题行为灰色背景,行标题为粗体。

现在,您可以开始考虑在同一电子表格中包含多个页面或工作表,添加公式,甚至包括图形,以便真正提高输出水平!

结论

本文研究了几种以标准格式生成表格数据的方法,从基本CSV文件到完整的ODS文件,可以通过手工(手动生成所有必需的文件,目录和压缩结​​果)或使用适当的库来进行处理。 通过一些额外的工作,您还可以生成美观的电子表格。 用户欣赏使他们的工作变得更容易,并且制作现成的电子表格非常合适。 现在,您可以开始将此功能添加到您自己的网页和服务中!


翻译自: https://www.ibm.com/developerworks/web/library/wa-odf/index.html

odf uof

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值