冰蓝科技
|
028-81705109
|
|
微信扫一扫
|

Spire.Cloud 纯前端文档控件

Spire.XLS for Java 15.10.5 现已正式发布。该版本优化了加载 Excel 文档时的内存消耗。同时,还修复了在获取复选框、加载大文件、复制工作表格式及保存文件等场景中出现的多个问题。更多详情如下:

优化:

问题修复:


获取 Spire.XLS for Java 15.10.5 请点击:

https://www.e-iceblue.cn/Downloads/Spire-XLS-JAVA.html

Spire.XLS 15.10.3 现已发布。本次更新新增了默认支持读取 Office 缓存的云字体的功能,使其在支持系统字体目录和内存字体的基础上,能够自动识别和加载云字体。同时,本版本调整了 AddDigitalSignature() 和 IDigitalSignatures.Add() 方法的参数定义,并修复了多个已知问题,从而提升了整体的稳定性和兼容性。详细信息如下:

新功能:

调整:

问题修复:


下载Spire.XLS 15.10.3,请点击:

https://www.e-iceblue.cn/Downloads/Spire-XLS-NET.html

Spire.Doc 13.10.3 现已发布,该版本支持从 Word 文件中提取指定范围的页面并保存为另一个文档。同时,修复了一系列与 Word 到 PDF 转换相关的问题。更多详情如下。

新功能:

问题修复:


获取Spire.Doc 13.10.3,请点击:

https://www.e-iceblue.cn/Downloads/Spire-Doc-NET.html

Spire.PDF 11.10.4 现已正式发布。该版本支持验证时间戳服务 URL 地址的有效性,并成功修复了一些在转换和比较PDF文档时出现的问题。详情请查阅以下内容。

新功能:

问题修复:


获取Spire.PDF 11.10.4,请点击:

https://www.e-iceblue.cn/Downloads/Spire-PDF-NET.html

Python 将 CSV 转换为 XML

CSV 因其简洁和跨平台的广泛支持,是最常见的表格数据交换格式之一。然而,当需要处理结构化应用程序、配置文件或层次化数据时,XML 通常成为首选格式,因为它能够表示嵌套关系并提供更严格的数据验证。

在本指南中,我们将探讨如何使用 Spire.XLS for Python 将 CSV 文件转换为 XML。你将学习如何将 CSV 转换为 Excel XML 格式以及 标准 XML 。同时,我们还将介绍如何清理和预处理真实世界中的 CSV 文件——处理无效表头、缺失值、特殊字符和嵌套字段等问题,以确保生成的 XML 输出始终有效且结构正确。

文章目录

为什么要将 CSV 转换为 XML

为什么开发者需要将 CSV 转 XML 呢?以下是一些实际应用场景:

  • 企业数据迁移 : 许多企业级应用程序(如 ERP 或 CRM 系统)在批量导入数据时要求 XML 格式。
  • 配置与元数据 : XML 常用于存储结构化元数据,而原始数据可能以 CSV 形式提供。
  • 互操作性 : 某些行业(如金融、医疗、政府)仍大量依赖 XML 数据格式进行数据交换。
  • 可读性报告 :XML 可以表示层次化数据,比扁平化的 CSV 文件更具描述性。
  • 数据验证 :XML 可通过 XSD 模式验证数据完整性,而 CSV 无法直接实现此功能。

CSV 以简洁取胜,XML 以结构见长。通过两者的互相转换,你可以兼得两种格式的优势。

准备工作

在开始编写代码之前,请确保准备好以下环境:

  • Python 3.7 及以上版本
  • Spire.XLS for Python → 一款功能强大的专业 Excel 操作库
  • 标准 Python 库 → xml.etree.ElementTree、csv 和 re

通过 pip 安装 Spire.XLS(假设系统中已安装 Python 和 pip):

pip install spire.xls

此外,请准备一个测试用 CSV 文件,例如:

员工ID,姓名,部门,职位,入职日期,薪资
1001,张三,技术部,软件工程师,2021-03-15,15000
1002,李四,市场部,市场专员,2022-07-01,12000
1003,王五,技术部,产品经理,2020-11-10,18000
1004,赵六,人力资源部,招聘经理,2019-05-22,14000

将 CSV 转换为 Excel XML 格式

第一种方法是将 CSV 转换为 Excel 兼容的 XML 格式,也称为 SpreadsheetML (Excel 2003 引入)。这种格式可以被 Excel 直接打开。

使用 Spire.XLS,这一过程非常简单:

from spire.xls import *

# 创建 Workbook
workbook = Workbook()

# 加载 CSV 文件
workbook.LoadFromFile("input.csv", ",", 1, 1)

# 保存为 Excel XML格式
workbook.SaveAsXml("output.xml")

# 释放资源
workbook.Dispose()

工作原理

  1. 读取 CSV 文件 : 使用 LoadFromFile() 方法将 CSV 文件读取到工作簿中。
  2. 保存为Excel XML 格式 : 使用 SaveAsXml() 方法保存为 Excel XML 格式。

效果图

将 CSV 转换为 Excel XML

你可能喜欢:使用 Python 将CSV 转为 Excel

将 CSV 转换为标准 XML

更多时候,你可能需要如下所示标准的XML 结构,而不是 Excel 兼容格式:

<Employee>
  <employee_id>1001</employee_id>
  <name>张三</name>
  <department>技术部</department>
  <position>软件工程师</position>
  <hire_date>2021-03-15</hire_date>
  <salary>15000</salary>
</Employee>

实现方式如下:

from spire.xls import *
import xml.etree.ElementTree as ET
from xml.dom import minidom

def chinese_to_english_tag(chinese_header):
    """
    将特定的中文列名转换为英文XML标签
    """
    mapping = {
        '员工ID': 'employee_id',
        '姓名': 'name', 
        '部门': 'department',
        '职位': 'position',
        '入职日期': 'hire_date',
        '薪资': 'salary'
    }
    # 去除前后空格后查找映射
    cleaned_header = chinese_header.strip()
    return mapping.get(cleaned_header, cleaned_header)

# Step 1: 加载 CSV 文件
workbook = Workbook()
workbook.LoadFromFile(r"C:\Users\Administrator\Desktop\input.csv", ",", 1, 1)
sheet = workbook.Worksheets[0]

# Step 2: 创建根节点
root = ET.Element("Employees")

# Step 3: 处理表头 - 中文列名转英文
headers = []
for col in range(1, sheet.Columns.Count + 1):
    cell_value = sheet.Range[1, col].Value
    if not cell_value:
        break
    english_tag = chinese_to_english_tag(str(cell_value))
    headers.append(english_tag)

# Step 4: 添加数据行
for row in range(2, sheet.Rows.Count + 1):
    if not sheet.Range[row, 1].Value:
        break
    employee = ET.SubElement(root, "Employee")
    for col, english_header in enumerate(headers, start=1):
        cell_value = sheet.Range[row, col].Value
        field = ET.SubElement(employee, english_header)
        field.text = str(cell_value) if cell_value is not None else ""

# Step 5: 保存为格式化的 XML 文件
xml_str = ET.tostring(root, encoding='utf-8')
pretty_xml = minidom.parseString(xml_str).toprettyxml(indent="  ")

with open("output/standard.xml", 'w', encoding='utf-8') as f:
    f.write(pretty_xml)

# 释放资源
workbook.Dispose()

工作原理

  1. 读取 CSV 文件 :使用 LoadFromFile() 方法导入 CSV 数据,加载到工作表中。
  2. 创建 XML 根节点 :创建根节点 <Employees>,用于存放所有员工信息。
  3. 转换表头 :读取第一行表头,通过映射函数将中文列名转换为对应的英文标签,例如“员工ID”→employee_id,以确保生成的 XML 符合英文命名规范。
  4. 生成数据节点 :从第二行开始遍历数据,为每一行创建 <Employee> 元素,并根据表头生成子标签填入数据。
  5. 格式化并保存 :对生成的 XML 进行缩进美化后,保存为 standard.xml 文件。

效果图

将 CSV 转换为标准 XML

你可能喜欢:如何在 Python 中将 CSV 转换为 JSON

处理现实 CSV 数据问题

将“完美”的 CSV 转换为 XML 很容易,但实际 CSV 往往并不理想。以下是常见问题及对应解决方案:

  1. 无效的表头名称
  • 问题:如 “Employee ID” 或 “123Name” 在 XML 中无效。
  • 解决:将空格替换为下划线 _,或为数字开头的列名添加前缀。
  1. 空值或缺失值
  • 问题:缺失值可能导致 XML 结构错误。
  • 解决:将空值替换为占位符(如 NULL、Unknown、0)。
  1. 特殊字符
  • 问题:如 <, >, & 会破坏 XML。
  • 解决:使用转义字符 &lt;, &gt;, &amp;。
  1. CSV 中的嵌套数据
  • 问题:某些单元格包含多个值,如:
OrderID,Customer,Products
1001,张三,"电脑;鼠标;键盘"

若直接转换,将丢失层次结构。

  • 解决:检测并拆分嵌套字段,生成层次化 XML:
<Products>
  <Product>电脑</Product>
  <Product>鼠标</Product>
  <Product>键盘</Product>
</Products>
  1. 中文列名转换为英文
  • 问题: XML 标签通常要求为英文,若 CSV 文件使用中文列名(如“姓名”、“部门”),生成的 XML 标签不符合通用标准。
  • 解决: 在生成 XML 前,将中文列名映射为对应的英文标签,例如“姓名”→“name”,“部门”→“department”。(如“将 CSV 转换为标准 XML”部分代码所示)

使用 clean_csv 自动清理

可使用以下辅助函数自动预处理 CSV (不包含中文列名转换为英文):

import csv
import re

def clean_csv(input_file, output_file, nested_columns=None, nested_delimiter=";"):
    if nested_columns is None:
        nested_columns = []

    cleaned_rows = []

    # 转义 XML 特殊字符
    def escape_xml(text):
        return (text.replace("&", "&amp;")
                    .replace("<", "&lt;")
                    .replace(">", "&gt;")
                    .replace('"', "&quot;")
                    .replace("'", "&apos;"))

    with open(input_file, "r", encoding="utf-8") as infile:
        reader = csv.reader(infile)
        headers = next(reader)

        # 清理表头
        cleaned_headers = []
        for h in headers:
            h = h.strip()                              # 去除首尾空格
            h = re.sub(r"\s+", "_", h)                 # 将空格替换为下划线
            h = re.sub(r"[^a-zA-Z0-9_]", "", h)        # 移除非法字符
            if re.match(r"^\d", h):                    # 若表头以数字开头,则加前缀
                h = "Field_" + h
            cleaned_headers.append(h)

        cleaned_rows.append(cleaned_headers)

        # 读取所有行数据
        raw_rows = []
        for row in reader:
            # 将空单元格替换为 "NULL"
            row = [cell if cell.strip() != "" else "NULL" for cell in row]
            raw_rows.append(row)

    # 处理嵌套列(如多值列)
    if nested_columns:
        expanded_rows = [cleaned_headers]  # 保留表头
        for row in raw_rows:
            row_variants = [row]
            for col_name in nested_columns:
                if col_name not in cleaned_headers:
                    continue
                col_index = cleaned_headers.index(col_name)
                temp = []
                for variant in row_variants:
                    cell_value = variant[col_index]
                    # 仅按嵌套分隔符拆分,不影响 XML 特殊字符
                    if nested_delimiter in cell_value:
                        items = [item.strip() for item in cell_value.split(nested_delimiter)]
                        for item in items:
                            new_variant = variant.copy()
                            new_variant[col_index] = item
                            temp.append(new_variant)
                    else:
                        temp.append(variant)
                row_variants = temp
            expanded_rows.extend(row_variants)
        cleaned_rows = expanded_rows
    else:
        cleaned_rows.extend(raw_rows)

    # 展开后再转义特殊字符
    final_rows = [cleaned_rows[0]]  # 保留表头
    for row in cleaned_rows[1:]:
        final_row = [escape_xml(cell) for cell in row]
        final_rows.append(final_row)

    # 写入清理后的 CSV 文件
    with open(output_file, "w", newline="", encoding="utf-8") as outfile:
        writer = csv.writer(outfile)
        writer.writerows(final_rows)

print(f"清理后的 CSV 已保存至 {output_file}")

你可以通过传入输入和输出 CSV 文件路径来调用 clean_csv 函数,并可选地指定需要展开嵌套值的列。

# 文件路径
input_file = r"C:\Users\Administrator\Desktop\input.csv"
output_file = r"C:\Users\Administrator\Desktop\cleaned_output.csv"

# 指定可能包含嵌套值的列
nested_columns = ["Products"]  # 你也可以添加更多,例如 ["Products", "Reviews"]

# 调用 clean_csv 函数
clean_csv(input_file, output_file, nested_columns=nested_columns, nested_delimiter=";")

该函数可确保 CSV 在转换为 XML 前干净、有效,功能包括:

  • 清理表头(符合 XML 命名规则)
  • 处理空单元格
  • 拆分嵌套列值
  • 转义特殊字符
  • 生成 UTF-8 编码的清洁 CSV 文件

总结

使用 Spire.XLS for Python 将 CSV 转换为 XML,不仅高效,而且具备极强的灵活性。无论是快速导出、结构化集成,还是复杂的业务数据转换,都能轻松应对。

  • 快速导出: 如果只是为了让文件可被 Excel 直接读取,采用 Excel XML 格式是最快捷的方式。
  • 自定义结构: 若需生成具有特定标签或层级关系的 XML,可借助 xml.etree.ElementTree 构建标准 XML 文档,实现高度定制。
  • 数据清理与增强: 面对真实环境中格式不规范或存在嵌套数据的 CSV,可先使用 clean_csv() 函数进行清洗,统一字段名、展开嵌套列,并自动转义特殊字符,确保生成的 XML 结构规范、可解析。

从企业系统集成、报表归档,到旧系统的数据迁移,这一流程充分结合了 CSV 的简洁性XML 的结构化优势 ,为数据交换与自动化处理提供了稳健、高可维护的解决方案。

常见问题(FAQs)

Q1. 可以转换非常大的 CSV 文件吗?

可以,但建议采用流式处理(逐行处理)以避免内存问题。

Q2. Spire.XLS 是否支持将 CSV 转换为标准 XML?

支持。保存为 Excel XML 是内置功能,但自定义 XML 仍需代码实现。

Q3. 如何自动处理特殊字符?

可使用 escape_xml 辅助函数或 Python 内置的 xml.sax.saxutils.escape()。

Q4. 如果 CSV 有多个嵌套列怎么办?

调用 clean_csv 时,可在 nested_columns 参数中传入多个列名。

Q5. 可以验证生成的 XML 吗?

可以。生成 XML 后,可根据 XSD 模式进行验证。

申请临时License

如果您需要去除生成文档中的评估提示或解除功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。

Spire.PDF for C++ 11.10.0 现已正式发布。最新版本修复了提取 PDF 页面文本抛异常的问题。详情请查阅下方的内容。

问题修复:


获取 Spire.PDF for C++ 11.10.0 请点击:

Spire.PDF for C++ 下载页面

Spire.Presentation for Java 10.10.2 现已发布。本次更新新增支持将 Markdown 转换为 PPTX 文件,以及将 SVG 转换为 Shape,同时增强了 PPT 转 PDF 的转换功能。此外,本次更新还修复了一些已知问题,例如添加的 LaTeX 公式渲染不正确的问题。详情如下:

新功能:

问题修复:


获取 Spire.Presentation for Java 10.10.2,请点击以下链接:

https://www.e-iceblue.cn/Downloads/Spire-Presentation-JAVA.html

Spire.Presentation 10.10.1 现已发布,此更新引入了设置音频淡入和淡出持续时间的功能,以及裁剪音频的能力。以下是详细信息:

新功能:


Spire.Presentation 10.10.1 支持设置音频淡入和淡出持续时间

https://www.e-iceblue.cn/Downloads/Spire-Presentation-NET.html

TXT 文本文件转 CSV Python 教程

在 Python 中处理数据时,将 TXT 文本文件转换为 CSV 是数据分析、报表生成或跨应用共享数据的常见需求。TXT 文件通常存储非结构化的纯文本,直接处理较为繁琐,而 CSV 文件能将数据组织成行和列,更便于分析和处理。本文将详细介绍如何使用 Python 实现 TXT 文件转 CSV,包括单文件转换、批量转换以及处理不同分隔符的技巧。

目录

CSV 文件简介

CSV(逗号分隔值)文件是一种基于文本的简单文件格式,用于存储表格数据。每一行表示一条记录,行内的值用逗号、制表符或自定义分隔符分隔。

CSV 文件具有以下优势:

  • **广泛兼容:**Excel、Google Sheets、数据库及 Python、R、SQL 等编程环境均可读取。
  • **简单易用:**可方便地导入、导出和进行数据处理与分析。

在实际应用中,CSV 文件可用来存储联系人信息、销售数据、日志数据等结构化数据,便于后续处理和分析。

安装 Python TXT 转 CSV 库

Spire.XLS for Python是一个功能强大的库,不仅支持创建和编辑 Excel 文件,还能高效操作 CSV 文件,且无需安装 Microsoft Excel。借助 Spire.XLS,开发者可以轻松实现 TXT 转 CSV、数据写入、表格格式处理、公式计算以及批量文件操作等任务。

Python TXT 转 CSV 库 - Spire.XLS for Python

你可以运行以下命令直接从 PyPI 安装该库:

pip install Spire.XLS

如果需要安装指导,请参考如何安装 Spire.XLS for Python

在 Python 中将单个 TXT 文件转换为 CSV

将单个TXT文本文件转换为 CSV 非常简单,只需以下几个步骤即可完成:

  • 读取 TXT 文件:加载TXT文件并逐行读取文本内容。
  • 分割文本数据:根据分隔符(如空格、制表符或逗号)拆分字段。
  • 写入 CSV 文件:使用 Spire.XLS 将数据写入新的 CSV 文件。
  • 验证输出:在 Excel、Google Sheets 或文本编辑器中检查 CSV 文件。

示例代码:

下面的代码示例展示如何使用 Python 导出 TXT 文本文件为 CSV:

from spire.xls import *

# 读取 TXT 文件
with open("data.txt", "r", encoding="utf-8") as file:
    lines = file.readlines()

# 处理每行数据(按空格分割,可根据需要更改分隔符)
processed_data = [line.strip().split() for line in lines]

# 创建 Excel 工作簿
workbook = Workbook()
# 获取第一个工作表
sheet = workbook.Worksheets[0]

# 将处理后的数据写入工作表
for row_num, row_data in enumerate(processed_data):
    for col_num, cell_data in enumerate(row_data):
        sheet.Range[row_num + 1, col_num + 1].Value = cell_data

# 将工作表保存为 CSV 文件(UTF-8 编码)
sheet.SaveToFile("Txt转Csv.csv", ",", Encoding.get_UTF8())
# 释放工作簿资源
workbook.Dispose()

TXT 转 CSV 输出结果:

使用 Spire.XLS 在 Python 中 将 TXT 文本文件转换为 CSV

如果你还希望将 TXT 文件转换为 Excel 文件,可参考教程如何使用 Python 将 TXT 转 Excel

批量转换多个 TXT 文件为 CSV

如果你有多个文本文件需要自动转换为 CSV,可以遍历文件夹中的所有 .txt 文件,并逐一转换。

以下代码演示如何在 Python 中批量将多个 TXT 文件转换为 CSV:

import os
from spire.xls import *

# TXT 文件所在文件夹
input_folder = "txt_files"
output_folder = "csv_files"

# 如果输出文件夹不存在,则创建
os.makedirs(output_folder, exist_ok=True)

# 单个 TXT 文件转换函数
def convert_txt_to_csv(file_path, output_path):
    with open(file_path, "r", encoding="utf-8") as f:
        lines = f.readlines()

    processed_data = [line.strip().split() for line in lines if line.strip()]

    workbook = Workbook()
    sheet = workbook.Worksheets[0]

    for row_num, row_data in enumerate(processed_data):
        for col_num, cell_data in enumerate(row_data):
            sheet.Range[row_num + 1, col_num + 1].Value = cell_data

    sheet.SaveToFile(output_path, ",", Encoding.get_UTF8())
    workbook.Dispose()
    print(f"已转换 '{file_path}' -> '{output_path}'")

# 遍历文件夹中所有 TXT 文件并转换
for filename in os.listdir(input_folder):
    if filename.lower().endswith(".txt"):
        input_path = os.path.join(input_folder, filename)
        output_name = os.path.splitext(filename)[0] + ".csv"
        output_path = os.path.join(output_folder, output_name)

        convert_txt_to_csv(input_path, output_path)

Python TXT 转 CSV 高级技巧

在将文本文件转换为 CSV 时,不同文本文件可能存在格式差异或潜在错误,以下技巧可帮助你更高效地处理各种场景。

1. 处理不同分隔符

并非所有文本文件都使用空格分隔值。如果 TXT 文件使用制表符、逗号或其他字符,可调整 split() 函数以匹配分隔符:

  • 制表符分隔文件(.tsv):
processed_data = [line.strip().split('\t') for line in lines]
  • 逗号分隔文件:
processed_data = [line.strip().split(',') for line in lines]
  • 自定义分隔符(如 |):
processed_data = [line.strip().split('|') for line in lines]

这样可以确保数据在写入 CSV 前正确拆分为列。

2. 添加错误处理

读取或写入文件时,使用 try-except 捕获潜在错误,可增强脚本稳健性,避免意外崩溃:

try:
    # 你的代码
except Exception as e:
    print("错误:", e)

提示:使用清晰的错误信息提示便于理解问题所在。

3. 跳过空行

有些 TXT 文件可能包含空行,可在处理时过滤空行,避免在 CSV 中生成空行:

processed_data = [line.strip().split() for line in lines if line.strip()]

总结

本文介绍了如何使用 Spire.XLS for Python 在 Python 中将 TXT 文本文件转换为 CSV。通过这些方法,你可以轻松处理文本数据,使其适合分析、报表和共享。Spire.XLS 不仅支持单文件转换,还能实现批量处理,并可灵活应对不同分隔符和文本格式。

如果你在 Python TXT 转 CSV 转换过程中遇到问题或需要技术支持,可访问我们的支持论坛获取帮助。

常见问题解答:Python 文本转 CSV

Q1: 可以在未安装 Microsoft Excel 的情况下将 TXT 文件转换为 CSV 吗?

A1: 可以。Spire.XLS for Python 独立于 Excel,可直接创建和导出 CSV 文件。

Q2: 如何在 Python 中批量将多个 TXT 文件转换为 CSV?

A2: 使用循环读取文件夹中的所有 TXT 文件,并对每个文件应用转换逻辑。教程中提供了可直接使用的 Python 批量转换示例。

Q3: 转换时如何处理 TXT 文件中的空行或列数不一致的情况?

A3: 在处理过程中过滤空行,并检查列数一致性,以避免输出 CSV 中出现错误或空行。

Q4: 如何在 Python 中将带制表符或自定义分隔符的 TXT 文件转换为 CSV?

A4: 可根据 TXT 文件中的分隔符调整 split() 函数--制表符 (\t)、逗号或其他自定义字符,然后再写入 CSV。

使用 C# 通过模板生成 PDF

在企业应用、报表系统或财务工具的开发中,生成规范、专业的 PDF 文档是常见需求。与其在代码中硬编码布局,不如使用模板来提高开发效率。模板不仅能加快开发进程,还能确保品牌视觉与文档格式的一致性。

本文将介绍如何使用 Spire.PDF for .NET 在 C# 中通过 HTML 模板预设 PDF 模板 生成 PDF 文档,无论是需要动态布局还是快速替换占位符,都能灵活应对。

本文目录

Spire.PDF for .NET 是什么

Spire.PDF for .NET 是一款功能强大的 PDF 操作库,允许 .NET 开发者无需依赖 Adobe Acrobat 即可创建、读取、编辑和转换 PDF 文档。该库提供全面的 API 接口,适用于生成报表、发票、证书及其他 PDF 格式文件,非常适合在 C# 应用中进行自动化文档处理。

与本教程相关的主要功能包括:

  • HTML 转 PDF: 将网页或 HTML 字符串高保真地渲染为 PDF 文档。
  • 文本替换: 在现有 PDF 中查找并替换文本,非常适合模板表单填充。
  • 全面控制: 从文本、图像到安全性与批注,提供精细化控制能力。

在项目中配置 Spire.PDF

要在 C# 项目中通过模板生成 PDF,首先需将 Spire.PDF 引入项目中。对于 HTML 转 PDF 的场景,Spire.PDF 依赖外部渲染引擎(Qt WebEngine 或 Google Chrome)。本文以 Qt WebEngine为例。

步骤 1:安装 Spire.PDF

在 Visual Studio 的 NuGet 包管理器中运行以下命令:

Install-Package Spire.PDF

或从官方网站下载 Spire.PDF 安装包,并将 DLL 文件手动导入项目。

步骤 2:下载并配置 Qt 插件

  1. 根据系统下载对应的 Qt WebEngine 插件:

  2. 解压文件后可获得插件目录,例如:C:\plugins-windows-x64\plugins

  3. 在 C# 代码中注册插件路径:

HtmlConverter.PluginPath = @"C:\plugins-windows-x64\plugins";

在 C# 中通过 HTML 模板创建 PDF

HTML 模板非常适合需要表格、页眉页脚或复杂样式布局(如发票、报表)的文档。

步骤 1:构建带占位符的 HTML 模板

可在 HTML 中添加双花括号包裹的动态字段,例如:

<h1>发票</h1>
<p>发票编号: {{INVOICE_NUMBER}}</p>
<p>日期: {{INVOICE_DATE}}</p>
<p><strong>姓名: </strong> {{CUSTOMER_NAME}}</p>

步骤 2:使用运行时数据替换占位符

以下是一个生成发票 PDF 的完整示例代码:

using Spire.Additions.Qt;
using System.Drawing;
using Spire.Pdf.Graphics;

namespace CreatePdfFromHtmlTemplate
{
    class Program
    {
        static void Main(string[] args)
        {
            // 带有占位符变量的HTML模板
            string htmlTemplate = @"
                    <!DOCTYPE html>
                    <html lang=""zh"">
                    <head>
                      <meta charset=""UTF-8"">
                      <meta name=""viewport"" content=""width=device-width, initial-scale=1.0"">
                      <title>发票</title>
                      <style>
                        body {
                          font-family: ""SimHei"", ""黑体"", Tahoma, sans-serif;
                          margin: 40px auto;
                          padding: 20px;
                          max-width: 800px;
                          font-size: 20px;
                        }

                        h1 {
                          text-align: right;
                          font-size: 40px;
                          letter-spacing: 2px;
                          color: #222;
                          margin: 0 0 30px 0; 
                        }

                        .invoice-header, .invoice-footer {
                          margin-bottom: 50px;
                        }

                        .invoice-header {
                          display: flex;
                          justify-content: space-between;
                          align-items: center;
                          border-bottom: 3px solid #444;
                          padding-bottom: 10px;
                        }

                        .invoice-details {
                          margin: 20px 0;
                          padding: 15px;
                          background: #f5f5f5;
                          border-radius: 6px;
                        }

                        .invoice-details h2 {
                          font-size: 20px;
                          margin-bottom: 10px;
                          color: #444;
                        }

                        .info p {
                          margin: 2px 0;
                        }

                        table {
                          width: 100%;
                          border-collapse: collapse;
                          margin-top: 15px;
                        }

                        th, td {
                          padding: 10px;
                          border: 1px solid #ddd;
                          text-align: left;
                        }

                        th {
                          background-color: #efefef;
                          font-weight: 600;
                        }

                        tbody tr:nth-child(even) {
                          background: #f9f9f9;
                        }

                        .total {
                          margin-top: 20px;
                          text-align: right;
                          font-size: 15px;
                        }

                        .total p {
                          margin: 5px 0;
                        }

                        .total p span {
                          display: inline-block;
                          width: 120px;
                        }

                        .grand-total {
                          font-size: 18px;
                          font-weight: bold;
                          border-top: 2px solid #444;
                          margin-top: 10px;
                          padding-top: 10px;
                        }

                        .invoice-footer {
                          text-align: center;
                          font-size: 18px;
                          color: #666;
                          margin-top: 50px;
                          padding-top: 10px;
                        }
                      </style>
                    </head>
                    <body>

                      <div class=""invoice-header"">
                        <div>
                          <h2>公司名称</h2>
                          <p>123 商业街<br>重庆, 中国</p>
                        </div>
                        <div>
                          <h1>发票</h1>
                          <p>发票编号: {{INVOICE_NUMBER}}<br>日期: {{INVOICE_DATE}}</p>
                        </div>
                      </div>

                      <div class=""invoice-details"">
                        <h2>账单寄送至</h2>
                        <div class=""info"">
                          <p><strong>姓名:</strong> {{BILLER_NAME}}</p>
                          <p><strong>地址:</strong> {{BILLER_ADDRESS}}</p>
                          <p><strong>邮箱:</strong> {{BILLER_EMAIL}}</p>
                        </div>
                      </div>

                      <table>
                        <thead>
                          <tr>
                            <th>描述</th>
                            <th>数量</th>
                            <th>单价</th>
                            <th>行总计</th>
                          </tr>
                        </thead>
                        <tbody>
                          <tr>
                            <td>{{ITEM_DESCRIPTION}}</td>
                            <td>{{ITEM_QUANTITY}}</td>
                            <td>{{ITEM_UNIT_PRICE}}</td>
                            <td>{{ITEM_TOTAL}}</td>
                          </tr>
                          <!-- 这里可以添加更多行 -->
                        </tbody>
                      </table>

                      <div class=""total"">
                        <p><span>小计:</span> {{SUBTOTAL}}</p>
                        <p><span>税 ({{TAX_RATE}}%):</span> {{TAX}}</p>
                        <p class=""grand-total""><span>总计:</span> {{TOTAL}}</p>
                      </div>

                      <div class=""invoice-footer"">
                        <p>感谢您的惠顾!</p>
                        <p>如有任何疑问,请联系我们 该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。</p>  
                      </div>

                    </body>
                    </html>
                    ";

            // 发票的样本数据 - 与模板占位符匹配的键值对
            Dictionary<string, string> invoiceData = new Dictionary<string, string>()
            {
                { "INVOICE_NUMBER", "12345" },
                { "INVOICE_DATE", "2025-08-25" },
                { "BILLER_NAME", "张三" },
                { "BILLER_ADDRESS", "重庆市新北街123号" },
                { "BILLER_EMAIL", "zhangsan@ example.com" },
                { "ITEM_DESCRIPTION", "咨询服务" },
                { "ITEM_QUANTITY", "10" },
                { "ITEM_UNIT_PRICE", "$100" },
                { "ITEM_TOTAL", "$1000" },
                { "SUBTOTAL", "$1000" },
                { "TAX_RATE", "5" },
                { "TAX", "$50" },
                { "TOTAL", "$1050" }
            };

            // 用实际数据值填充HTML模板
            string populatedInvoice = PopulateInvoice(htmlTemplate, invoiceData);

            // 指定生成的PDF输出文件路径
            string outputFile = "HtmlToPdf.pdf";

            // 指定HTML转换器的插件路径(QT插件)
            string pluginPath = @"C:\plugins-windows-x64\plugins";

            // 设置HTML到PDF转换所需的插件路径
            HtmlConverter.PluginPath = pluginPath;

            // 使用指定设置将HTML字符串转换为PDF
            HtmlConverter.Convert(
                populatedInvoice,
                outputFile,
                true,                       // 启用JavaScript
                100000,                     // 超时(毫秒)
                new SizeF(595, 842),        // A4纸大小(595x842点)
                new PdfMargins(20),         // 四周20点边距
                LoadHtmlType.SourceCode     // 从源代码字符串加载HTML
            );

        }

        // 辅助方法: 用数据字典中的实际值替换模板占位符
        private static string PopulateInvoice(string template, Dictionary<string, string> data)
        {
            string result = template;
            foreach (var entry in data)
            {
                result = result.Replace("{{" + entry.Key + "}}", entry.Value);
            }
            return result;
        }
    }
}

实现原理

  1. 在 HTML 模板中定义形如 {{VARIABLE_NAME}} 的占位符。
  2. 使用字典存储实际数据的键值对,与模板占位符对应。
  3. 程序运行时将模板中的占位符替换为真实数据。
  4. 调用 Spire.PDF(配合 Qt 插件)将 HTML 渲染为 PDF 文件。

输出结果:

使用C#通过HTML模板创建PDF

在 C# 中通过 PDF 模板生成 PDF

有时设计团队会提供带有占位符(如 {PROJECT_NAME})的静态 PDF 模板。通过简单的文本替换即可将这些模板快速填充成正式文档。

示例:填充项目报告模板

using Spire.Pdf;
using Spire.Pdf.Texts;
using static Spire.Pdf.Texts.PdfTextReplaceOptions;

namespace GeneratePdfFromPdfTemplate
{
    class Program
    {
        static void Main(string[] args)
        {
            // 创建一个PdfDocument对象
            PdfDocument doc = new PdfDocument();

            // 加载一个PDF文件
            doc.LoadFromFile(@"C:\Users\Administrator\Desktop\Template.pdf");

            // 创建一个PdfTextReplaceOptions对象并指定选项
            PdfTextReplaceOptions textReplaceOptions = new PdfTextReplaceOptions();
            textReplaceOptions.ReplaceType = ReplaceActionType.WholeWord; // 替换类型设置为整词替换

            // 获取特定页面
            PdfPageBase page = doc.Pages[0];

            // 基于页面创建一个PdfTextReplacer对象
            PdfTextReplacer textReplacer = new PdfTextReplacer(page);
            textReplacer.Options = textReplaceOptions;

            // 旧字符串和新字符串的字典
            Dictionary<string, string> replacements = new Dictionary<string, string>()
            {
                { "{PROJECT_NAME}", "新网站开发" },
                { "{PROJECT_NO}", "2023-001" },
                { "{PROJECT MANAGER}", "爱丽丝·约翰逊" },
                { "{PERIOD}", "2023年第三季度" },
                { "{START_DATE}", "2023年7月1日" },
                { "{END_DATE}", "2023年9月30日" }
            };

            // 遍历字典进行文本替换
            foreach (var pair in replacements)
            {
                textReplacer.ReplaceText(pair.Key, pair.Value);
            }

            // 将文档保存为另一个PDF文件
            doc.SaveToFile("FromPdfTemplate.pdf");
            doc.Close();
        }
    }
}

实现原理

  1. 加载包含占位符的现有 PDF 文件。
  2. 使用字典存储占位符与实际数据的映射关系。
  3. 遍历字典并替换 PDF 中对应的文本。
  4. 将修改后的文档另存为新 PDF 文件。

限制说明: 此方法仅适用于短文本(如姓名、编号、日期等)的替换。对于多行文本或动态扩展的内容,它的效果不佳,因为PDF不会自动重新排版文本。对于较大的内容块,请使用HTML或Word模板。

输出结果:

使用C#通过替换PDF模板文本生成报告

Spire.PDF 支持更多文本替换设置,请参考:在 C# 中替换 PDF 文档中的文本

根据模板生成 PDF 最佳实践

选择合适的模板类型

  • HTML 模板: 适用于需要复杂样式、表格或长文本的文档灵活性最高。
  • PDF 模板: 适用于布局固定、仅需替换少量字段的文档(如表单、报告)。
  • Word 模板: 若文档源于 .docx 文件,可使用 Spire.Doc for .NET 进行占位符替换并导出为 PDF。

占位符设计

  • 使用独特且清晰的占位符格式(如 {NAME}、{DATE})避免误替换。
  • 保持一致的命名规范,减少维护错误。

测试与验证

  • 使用真实或代表性数据进行测试,检查文本对齐、换行与版面效果。

模板管理

  • 将模板文件与代码分离,方便设计人员独立维护。
  • 建立模板规范文档,定义命名、语法和样式要求。

常见问题解答

Q1:可以使用 Google Chrome 代替 Qt WebEngine 渲染 HTML 吗?

可以。对于复杂 HTML、CSS 或现代 JavaScript,建议使用 ChromeHtmlConverter 类,它能生成更精确的 PDF。

?详见教程:使用 ChromeHtmlConverter 将 HTML 转换为 PDF

Q2:在 PDF 模板中替换文本有哪些限制?

PDF 布局固定,替换文本不会自动重排。当新文本过长可能溢出,过短则留白。适用于可预测的字段内容(如姓名、日期等)。对于多行文本或动态内容,可使用 HTML 或 Word 模板,或借助 Spire.PDF 的绘图 API 直接绘制新文本块。

Q3:能否通过 Spire.PDF 从 Word 模板生成 PDF?

Spire.PDF 主要用于 PDF 操作,如需根据 Word 模板生成PDF,可使用 Spire.Doc for .NET 替换 Word 模板内容,然后再保存为 PDF。

Q4:如何在模板生成的 PDF 中插入图片、Logo 或签名?

  • 在 PDF 中,可通过 PdfCanvas.drawImage() 方法绘制图片。
  • 在 HTML 模板中,可直接使用 标签。

这样即可轻松添加公司 Logo、水印或电子签名。

结论

使用 Spire.PDF 在 C# 中基于模板生成 PDF,是提升文档自动化效率的理想方式。无论选择 HTML 模板还是现有 PDF 模板,开发者都能轻松创建内容准确、版面统一、外观专业的文件。通过在开发流程中引入模板机制,不仅能显著减少重复性工作,还能确保品牌风格与格式的一致性。

在实施过程中,合理选择模板类型、规范占位符设计,并在部署前充分测试真实数据,能够帮助你获得更稳定的输出效果。随着项目的深入,还可以结合 Spire.PDF 的高级功能,如数字签名、加密与批注等,实现更安全、更智能的文档处理方案。

通过这一方法,你的团队将能够在保证质量与一致性的同时,大幅提升 PDF 文档的生成速度与管理效率,从而让自动化办公与报告生成更加高效、可控。

申请临时 License

如果您需要去除生成文档中的评估提示或解除功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。