【发布时间】:2021-11-08 17:23:19
【问题描述】:
我希望从代表命名实体的索引中注释 XML 中的文本:
glossary = ['Paris', 'Vincennes', 'France', 'Guy de Maupassant', 'Maurice Ravel']
我在 Stack 上找到了一个解决方案(由 @Brad Clements 提供)在此处对 XML 进行部分注释:insert tags in ElementTree text
对于 XML:<TEI><teiHeader></teiHeader><body><p>Paris est la capitale de France et Vincennes n'est pas loin.</p><p> Guy de Maupassant et Maurice Ravel inaugurent une nouvelle statue à Paris.</p></body></TEI>
它适用于小于 1 的单词,例如“Paris”、“Vincennes”或“France”,但不适用于索引中的其他单词。
我目前的输出是:<?xml version="1.0"?> <TEI><teiHeader/><body><p><entity>Paris</entity> est la capitale de <entity>France</entity> et <entity>Vincennes</entity> n'est pas loin. </p><p>Guy de Maupassant et Maurice Ravel inaugurent une nouvelle statue à <entity>Paris.</entity> </p></body></TEI>
预期输出:<?xml version="1.0"?> <TEI><teiHeader/><body><p><entity>Paris</entity> est la capitale de <entity>France</entity> et <entity>Vincennes</entity> n'est pas loin. </p><p><entity>Guy de Maupassant</entity> et <entity>Maurice Ravel</entity> inaugurent une nouvelle statue à <entity>Paris.</entity> </p></body></TEI>
我尝试改编的代码(取自insert tags in ElementTree text):
from lxml import etree
import string
import itertools
stylesheet = etree.XML("""
<xsl:stylesheet version="1.0"
xmlns:btest="uri:bolder"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*">
<xsl:copy />
</xsl:template>
<xsl:template match="*">
<xsl:element name="{name(.)}">
<xsl:copy-of select="@*" />
<xsl:apply-templates select="text()" />
<xsl:apply-templates select="./*" />
</xsl:element>
</xsl:template>
<xsl:template match="text()">
<xsl:copy-of select="btest:bolder(.)/node()" />
</xsl:template>
</xsl:stylesheet>
""")
glossary = ['Paris', 'Vincennes', 'France', 'Guy de Maupassant', 'Maurice Ravel']
def bolder(context, s):
results = []
r = None
# - Iteration over the index and the words contained in the sequence
for gw, word in itertools.zip_longest(glossary, s[0].split()):
# - Little preprocessing for words with punctuation
word_clean = word.translate(str.maketrans('', '', string.punctuation))
# 1) If word in sequence directly match with glossary (index) add tag
if word_clean in glossary:
if r is not None:
results.append(r)
r = etree.Element('r')
b = etree.SubElement(r, 'entity')
b.text = word
b.tail = ' '
results.append(r)
r = None
# 2) Otherwise take the word from the index and check that it is contained in the sequence
# (if the word is composed eg. First name + last name
# and that it is not None)
elif gw is not None and gw in s[0] and len(gw.split()) > 1:
# repeat the process to annotate
if r is not None:
results.append(r)
r = etree.Element('r')
b = etree.SubElement(r, 'entity')
b.text = gw
b.tail = ' '
results.append(r)
r = None
# 3) if none of the prerequisites, add text to output with no tag
else:
if r is None:
r = etree.Element('r')
r.text = '%s%s ' % (r.text or '', word)
if r is not None:
results.append(r)
return results
def test():
ns = etree.FunctionNamespace('uri:bolder')
ns['bolder'] = bolder
transform = etree.XSLT(stylesheet)
new = str(transform(etree.XML("""<TEI><teiHeader></teiHeader><body><p>Paris est la capitale de France et Vincennes n'est pas loin.</p><p> Guy de Maupassant et Maurice Ravel inaugurent une nouvelle statue à Paris.</p></body></TEI>""")))
print(new)
if __name__ == "__main__":
test()
但输出仍然不足(重复和遗漏):
<?xml version="1.0"?>
<TEI><teiHeader/><body><p><entity>Paris</entity> est la capitale de <entity>France</entity> et <entity>Vincennes</entity> n'est pas loin. </p><p>Guy de Maupassant <entity>Guy de Maupassant</entity> <entity>Maurice Ravel</entity> Ravel inaugurent une nouvelle statue à <entity>Paris.</entity> </p></body></TEI>
如何改进上述解决方案以正确匹配仅形成一个实体的混合词?提前致谢。美好的一天。
【问题讨论】:
标签: python-3.x xml xslt lxml