我正在根据用户在表格中输入的内容来创建Word文档。但是,当用户输入unicode控制字符,并尝试使用python-docx软件包从其中生成一个单词文件时,会发生以下错误:
File "src\lxml\apihelpers.pxi", line 1439, in lxml.etree._utf8
ValueError: All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters
我设法解决了这个问题,方法是在每次请求之前检查表单中是否有无效的xml字符(我有很多可能发生此问题的表单),并从字段中删除了所有无效的xml字符。然后,我制作一个新的不可变多字典,并用清除后的文本填充它。
from docx import Document
from docx.shared import Inches
from flask import Flask, render_template_string, request
from werkzeug.datastructures import ImmutableMultiDict
def valid_xml_char_ordinal(c):
codepoint = ord(c)
return (0x20 <= codepoint <= 0xD7FF or codepoint in (0x9, 0xA, 0xD) or
0xE000 <= codepoint <= 0xFFFD or 0x10000 <= codepoint <= 0x10FFFF)
app = Flask(__name__)
@app.before_request
def before_request():
if 'check_form_xml_validity' in request.form:
tuple_list = []
for field_name in request.form:
all_field_values = request.form.getlist(field_name)
for field_value in all_field_values:
cleaned_field_value = ''.join(c for c in field_value if valid_xml_char_ordinal(c))
tuple_list.append((field_name, cleaned_field_value))
request.form = ImmutableMultiDict(tuple_list)
@app.route('/', methods=['GET', 'POST'])
def form_test():
if request.method == 'GET':
x = '' # this seemingly empty string is not empty, but contains a bunch of control characters
return render_template_string(
"""<form action="{{ url_for('form_test') }}" method="post">
<input name="some_field" value="{{x}}"><br>
check the xml validity of this form? <br>
<input type="checkbox" checked name="check_form_xml_validity"><br>
<button>submit</button>
</form>""",
x=x)
else:
doc = Document()
p = doc.add_paragraph(request.form['some_field'])
return 'yay'
并且此方法完美地工作。但是,我似乎不可能是唯一一个遇到此问题的人,但是我找不到任何干净的解决方案。所以问题是,我真的应该以当前的方式解决这个问题吗?这很繁琐,感觉就像我在某个地方可以解决此问题的Flask或python-docx设置或参数一样。
该示例具有完整的功能,并且如果选中了此复选框,则将执行before_request
函数。如果未选中该复选框,则不会执行该复选框,并且将显示上述服务器错误。
控制字符为:U+000C : <control-000C> (FORM FEED [FF])
答案 0 :(得分:2)
unicode中有大量的控制字符。因此,基本上,您需要删除控制字符,这是Unicode字符中的类别之一。为此,我建议您使用unicodedata.category模块中的unicodedata。
请参见下面的代码:
import unicodedata
def remove_control_chars(s):
return "".join(ch for ch in s if unicodedata.category(ch)[0] != "C")