【问题标题】:How to replace attribute name in an html file while parsing it with lxml?用lxml解析时如何替换html文件中的属性名称?
【发布时间】:2014-03-14 03:56:06
【问题描述】:

我有一个 xml 文件,我需要根据每个 p 元素的 dfn 文本替换类属性的值。所以,我有一个这种 html 文件:

<html>
  <head></head>
  <body>
    <p class ='person'><dfn>New-York</dfn>
    <p class = 'place'><dfn>John Doe</dfn>
  </body>
</html>

我想解析这个文档并将类属性的所有值替换为正确的值。为了定义 dfn-text 是一个地方还是一个人,我的脚本中已经有一组条件。所以,我想获得与输出相同的 html 文件,但具有正确的类:

<html>
  <head></head>
  <body>
    <p class ='**place**'><dfn>New-York</dfn>
    <p class = '**person**'><dfn>John Doe</dfn>
  </body>
</html>

到目前为止,我试图实现它寻找dfn的祖先p及其属性'class',然后尝试用replace()函数替换它,但它并没有真正起作用:

filename = open('file.html', 'r+')
tree = etree.parse(filename)

def f1():
  for dfn in tree.getiterator('dfn'):
    def_text = dfn.text
    if def_text == 'New York'  #a list of conditions in my real script, New York is an example only):

      class1 = ''.join(dfn.xpath('ancestor::p//@class') 

      filename.write(class1.replace('person', 'place'))

我得到的只是同一个文件,但在末尾附加了一行“place”...

【问题讨论】:

  • “我得到的只是同一个文件,但在结尾附加了一行 'place'...” – 当然这就是你得到的全部,因为你并没有真正在任何地方操作 XML - 您所做的只是将某些内容写入以r+ 模式打开的文本文件,那么您如何期望结果是其他任何内容......?
  • 哦,您对我的问题和讽刺评论的减号非常有帮助!我已经可以看到它不起作用。我希望能有更好的人来回答一些有用的问题。

标签: html parsing replace lxml


【解决方案1】:

使用lxml with xslt 转换您的html,例如:

from lxml import etree

h = '''<html>
  <head></head>
  <body>
    <p class ='person'><dfn>New-York</dfn></p>
    <p class = 'place'><dfn>John Doe</dfn></p>
  </body>
</html>'''
doc = etree.fromstring(h, etree.HTMLParser())

xsl = '''<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>
 <xsl:template match="p">
    <xsl:variable name="original-class" select="string(@class)" />
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:if test="dfn[text()='New-York']">
          <xsl:attribute name="class">
            <xsl:value-of select="concat('**', $original-class, '**')"/>
          </xsl:attribute>
        </xsl:if>
        <xsl:apply-templates select="node()"/>
    </xsl:copy>
   </xsl:template>
</xsl:stylesheet>'''
xslt_root = etree.XML(xsl)
transform = etree.XSLT(xslt_root)
result_tree = transform(doc)
print result_treeoutput:

输出:

$ python x.py 
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head>
  <body>
    <p class="**person**"><dfn>New-York</dfn></p>
    <p class="place"><dfn>John Doe</dfn></p>
  </body>
</html>

【讨论】:

  • 非常感谢!这真的看起来像我需要的))但是,我仍然有一个小问题:这段代码将更改应用于整个文档,所有类都变为“人”或“地点”,这取决于我在模板中在 concat 之后指示的内容。我需要根据 dfn 的内容更改它们。如果“dfn-text”是一个人,则将其祖先的类更改为“人”。是否可以将模板仅应用于一个 p-tag,即相关“dfn”的祖先?
  • 我尝试过这样的事情:for dfn in htree.getiterator('dfn'): def_text = dfn.text if def_text == 'New_york': xslt_root = etree.XML(xsl) transform = etree.XSLT(xslt_root) p = dfn.xpath('ancestor::p') result_tree = transform(p) 我知道 transform(p) 不起作用,但我尝试展示这个想法 - 仅将转换应用于给定的祖先 p dfn.
  • 答案已更新,xslt 确实是要走的路,尝试使用 &lt;xsl:if test="p[text()='New-York']"&gt; 之类的东西匹配您要应用转换的标签
  • 感谢您的回答!我终于使用了另一种方法来解决它,但我认为我可能会使用您关于模板的想法来处理生成的 html 文件中的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-05
  • 1970-01-01
  • 2021-09-07
  • 1970-01-01
  • 1970-01-01
  • 2021-11-24
  • 1970-01-01
相关资源
最近更新 更多