【问题标题】:insert tags in ElementTree text在 ElementTree 文本中插入标签
【发布时间】:2010-12-30 16:34:00
【问题描述】:

我正在使用 Python ElementTree 模块来操作 HTML。 我想强调某些词,我目前的解决方案是:

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 中遗漏了一些东西!

【问题讨论】:

    标签: python html lxml elementtree


    【解决方案1】:

    您也可以使用 xslt 和自定义 xpath 函数来执行此操作。

    下面是一个例子。它仍然需要一些工作,例如清理元素末尾的额外空白和处理混合文本,但这是另一个想法。

    鉴于此输入:

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

    词汇表包含两个词: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()

    【讨论】:

      【解决方案2】:

      虽然 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'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多