正则表达式以XML格式解析模板标记

时间:2011-05-04 03:08:46

标签: python xml regex lxml

我需要解析一些XML来提取嵌入式模板标签以进行进一步的解析。不过,我似乎无法弯曲Python的正则表达式来做我想做的事情。

英文:当模板标记包含在行的任何位置时,删除该特定行的所有XML,并仅保留模板标记。

我整理了一个测试用例来演示。这是原始的XML:

<!-- regex_trial.xml -->
<w:tbl>
    <w:tr>
        <w:tc><w:t>Header 1</w:t></w:tc>
        <w:tc><w:t>Header 2</w:t></w:tc>
        <w:tc><w:t>Header 3</w:t></w:tc>
    </w:tr>
     <w:tr>
        <w:tc><w:t>{% for i in items %}</w:t></w:tc>
        <w:tc><w:t></w:t></w:tc>
        <w:tc><w:t></w:t></w:tc>
    </w:tr>
    <w:tr>
        <w:tc><w:t>{{ i.field1 }}</w:t></w:tc>
        <w:tc><w:t>{{ i.field2 }}</w:t></w:tc>
        <w:tc><w:t>{{ i.field3 }}</w:t></w:tc>
    </w:tr>
    <w:tr>
        <w:tc><w:t>{% endfor %}</w:t></w:tc>
        <w:tc><w:t></w:t></w:tc>
        <w:tc><w:t></w:t></w:tc>
    </w:tr>
</w:tbl>

这是期望的结果:

<!-- regex_desired_result.xml -->
<w:tbl>
    <w:tr>
        <w:tc><w:t>Header 1</w:t></w:tc>
        <w:tc><w:t>Header 2</w:t></w:tc>
        <w:tc><w:t>Header 3</w:t></w:tc>
    </w:tr>
    {% for i in items %}
    <w:tr>
        <w:tc><w:t>{{ i.field1 }}</w:t></w:tc>
        <w:tc><w:t>{{ i.field2 }}</w:t></w:tc>
        <w:tc><w:t>{{ i.field3 }}</w:t></w:tc>
    </w:tr>
    {% endfor %}
</w:tbl>

这是我用来测试的一些python代码:

#!/usr/bin/env python
import re
f = open( 'regex_trial.xml', 'r' )
orig_xml = f.read()
f.close()
p = re.compile( '<w:tr.*?(?P<tag>{%.*?%}).*?</w:tr>', re.DOTALL )
new_xml = p.sub( '\g<tag>', orig_xml, 0 )
print new_xml

此正则表达式的实际结果为:

<!-- regex_trial.xml -->
<w:tbl>
    {% for i in items %}
    {% endfor %}
</w:tbl>

非常感谢任何帮助!如果我们能够解决这个问题,我们将能够从Django驱动的站点动态生成MS Word docx文件。谢谢!

更新:这是我使用的最终代码

from xml.etree import ElementTree
import cStringIO as StringIO

TEMPLATE_TAG = 'template_text'

tree = ElementTree.parse( 'regex_trial.xml' )
rows = tree.getiterator('tr')
for row in rows:
    for cell in row.getiterator('t'):
        if cell.text and cell.text.find( '{%' ) >= 0:
            template_tag = cell.text
            row.clear()
            row.tag = TEMPLATE_TAG
            row.text = template_tag
            break

output = StringIO.StringIO()
tree.write( output )
xml = output.getvalue()
xml = xml.replace('<%s>' % TEMPLATE_TAG, '')
xml = xml.replace('</%s>' % TEMPLATE_TAG, '')
print xml

感谢您的帮助!

2 个答案:

答案 0 :(得分:4)

请不要使用正则表达式解决此问题。

我很认真,用正则表达式解析XML很难,而且它使你的代码可以被其他任何人维护50倍。

lxml是pythonist用于解析XML的事实工具...请查看this article on Stack Overflow以获取示例用法。或者考虑this answer,其中应该是接受的答案。

我将其作为快速演示进行了攻击...它使用非空<w:tc>子项搜索<w:t>并在每个元素旁边打印好。

import lxml.etree as ET
from lxml.etree import XMLParser

def worthy(elem):
    for child in elem.iterchildren():
        if (child.tag == 't') and (child.text is not None):
            return True
    return False

def dump(elem):
    for child in elem.iterchildren():
        print "Good", child.tag, child.text

parser = XMLParser(ns_clean=True, recover=True)
etree = ET.parse('regex_trial.xml', parser)
for thing in etree.findall("//"):
    if thing.tag == 'tc' and worthy(thing):
        dump(thing)

...产量

Good t Header 1
Good t Header 2
Good t Header 3
Good t {% for i in items %}
Good t {{ i.field1 }}
Good t {{ i.field2 }}
Good t {{ i.field3 }}
Good t {% endfor %}

答案 1 :(得分:3)

从未使用正则表达式解析HTML或XML或SGML。

始终使用像lxml,libxml2或Beautiful这样的工具 - 他们会做得更聪明,更好 工作比你的代码。