1

HTML を操作するために Python ElementTreeモジュールを使用しています。特定の単語を強調したいのですが、現在の解決策は次のとおりです。

for e in tree.getiterator():
    for attr in 'text', 'tail':
        words = (getattr(e, attr) or '').split()
        change = False
        for i, word in enumerate(words):
            word = clean_word.sub('', word)
            if word.lower() in glossary:
                change = True
                words[i] = word.replace(word, '<b>' + word + '</b>')
        if change:
            setattr(e, attr, ' '.join(words))

上記は、各要素のテキストを調べて、見つかった重要な単語を強調しています。ただし、テキスト属性にHTMLタグを埋め込むことでこれを行います。これは、レンダリング時にエスケープされるため、次のように対処する必要があります。

html = etree.tostring(tree).replace('&gt;', '>').replace('&lt;', '<')

これは気持ち悪いのでちゃんとやりたいです。ただし、新しい要素を埋め込むには、強調されたテキストが同じ位置に表示されるように、「テキスト」属性と「テール」属性をシフトする必要があります。そして、上記のように反復する場合、これは非常に注意が必要です。

これを適切に行うためのアドバイスをいただければ幸いです。APIで見逃しているものがあると確信しています!

4

2 に答える 2

4

xslt とカスタム xpath 関数を使用してこれを行うこともできます。

以下に例を示します。要素の末尾にある余分な空白をクリーンアップしたり、混合テキストを処理したりするなど、まだいくつかの作業が必要ですが、それは別のアイデアです。

この入力が与えられた場合:


<html>
<head>
</head>
<body>
<p>here is some text to bold</p>
<p>and some more</p>
</body>
</html>

そして用語集には次の 2 つの単語が含まれています: some、bold

出力例は次のとおりです。


<?xml version="1.0"?>
<html>
<head/>
<body>
<p>here is <b>some</b> text to <b>bold</b> </p>
<p>and <b>some</b> more </p>
</body>
</html>

これがコードです。http://bkc.pastebin.com/f545a8e1dにも投稿しました


from lxml import etree

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 = ['some', 'bold']

def bolder(context, s):
    results = []
    r = None
    for word in s[0].split():
        if word in glossary:
            if r is not None:
                results.append(r)
            r = etree.Element('r')
            b = etree.SubElement(r, 'b')
            b.text = word
            b.tail = ' '
            results.append(r)
            r = None
        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') # register global namespace
    ns['bolder'] = bolder # define function in new global namespace
    transform = etree.XSLT(stylesheet)
    print str(transform(etree.XML("""<html><head></head><body><p>here is some text to bold</p><p>and some more</p></body></html>""")))

if __name__ == "__main__":
    test()


于 2010-01-03T04:17:29.077 に答える
1

ElementTreeは、ほとんどのXML処理タスクで非常に使いやすいですが、混合コンテンツでは不便です。DOMパーサーを使用することをお勧めします。

from xml.dom import minidom
import re

ws_split = re.compile(r'\s+', re.U).split

def processNode(parent):
    doc = parent.ownerDocument
    for node in parent.childNodes[:]:
        if node.nodeType==node.TEXT_NODE:
            words = ws_split(node.nodeValue)
            new_words = []
            changed = False
            for word in words:
                if word in glossary:
                    text = ' '.join(new_words+[''])
                    parent.insertBefore(doc.createTextNode(text), node)
                    b = doc.createElement('b')
                    b.appendChild(doc.createTextNode(word))
                    parent.insertBefore(b, node)
                    new_words = ['']
                    changed = True
                else:
                    new_words.append(word)
            if changed:
                text = ' '.join(new_words)
                print text
                parent.replaceChild(doc.createTextNode(text), node)
        else:
            processNode(node)

また、正規表現を使用して単語を分割し、単語がくっつかないようにしました。

>>> ' '.join(ws_split('a b '))
'a b '
>>> ' '.join('a b '.split())
'a b'
于 2009-12-29T15:40:33.347 に答える