【问题标题】:tree = etree.fromstring(bytes(xml, encoding='utf-8')) TypeError: encoding without a string argumenttree = etree.fromstring(bytes(xml, encoding='utf-8')) TypeError: encoding without a string argument
【发布时间】:2020-05-29 12:19:38
【问题描述】:

我想编写一个函数来提取属性“fmc”的值和“标签”部分内的文本。我想使用正则表达式解决方案。

<?xml version = "1.0" encoding="UTF-8" standalone="yes" ?>
<corpus>
    <ver id="18" etude="EC1_Elec" elec="oui" niveau="1" critere="1.3" type="discours">
        <part code="EC1_Elec_IW04_0">Ça existe sur des gros parcs Hlm mais c'est macro.</part>
    </ver>
    <ver id="30" etude="EC1_Elec" elec="oui" niveau="2" critere="" origine="IW" type="discours" fmc="motives">
        <part code="EC1_Elec_IW01_0">Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.</part>
    </ver>
    <ver id="54" etude="EC1_Elec" elec="oui" niveau="1" critere="" origine="IW" type="discours" fmc="condition">
        <part code="EC1_Elec_IW10_0">Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.</part>
    </ver>
    <ver id="897" etude="EC3_Elec" elec="oui" niveau="4" critere="4.1" origine="TR" type="discours" fmc="obstacle">
        <part code="EC3_Elec_TR2_1">Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,</part>
        <iwer>Çava influencer la demande pour ce type de solution c'est ça ?</iwer>
        <part code="EC3_Elec_TR2_1">Je pense oui</part>
    </ver>
</corpus>

所以我根据上面的答案修改了这个函数以适应我的数据

代码

def review_extractor(xml, category='verbatim', do_lower=False):
    """
    Extract review and label
    """
    # use lxml...

    # parse the xml snippet into an object tree
    tree = etree.fromstring(bytes(xml, encoding='utf-8'))
    # find all elements that have "fmc" attribute
    for e in tree.findall(".//*[@fmc]"):
        label = e.xpath("./@fmc")[0]
        for c in e.getchildren("./part"):
            # print value of "fmc" attribute and text of child element
            print(f"{label:15}{c.text}")
            # 
        return label, c.text

所以对于我的例子,函数应该返回这个(标签前审查):

Label      review_text
motivation Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.

condition Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.

obstacle Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,

obstacle Je pense oui

【问题讨论】:

  • 你能澄清你的问题吗?为什么只使用正则表达式?
  • 你的缩进不对;你需要再编辑一次。
  • @kely789456123 我不确定这与我的评论有什么关系,你能详细说明一下吗?
  • 嗨@kely789456123 你不应该在人们花时间回答之后完全编辑你的问题。如果您还有其他问题,请提出新问题!
  • 永远不要使用正则表达式来处理 XML。 stackoverflow.com/questions/1732348/…

标签: python regex xml xml-parsing


【解决方案1】:

我知道您明确要求提供正则表达式解决方案,但作为替代方案,这里是使用 xml 解析器中内置的 python 之一,特别是 xml.etree.ElementTree

xml_string = """<?xml version = "1.0" encoding="UTF-8" standalone="yes" ?>
<corpus>
    <ver id="18" etude="EC1_Elec" elec="oui" niveau="1" critere="1.3" type="discours">
        <part code="EC1_Elec_IW04_0">Ça existe sur des gros parcs Hlm mais c'est macro.</part>
    </ver>
    <ver id="30" etude="EC1_Elec" elec="oui" niveau="2" critere="" origine="IW" type="discours" fmc="motives">
        <part code="EC1_Elec_IW01_0">Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.</part>
    </ver>
    <ver id="54" etude="EC1_Elec" elec="oui" niveau="1" critere="" origine="IW" type="discours" fmc="condition">
        <part code="EC1_Elec_IW10_0">Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.</part>
    </ver>
    <ver id="897" etude="EC3_Elec" elec="oui" niveau="4" critere="4.1" origine="TR" type="discours" fmc="obstacle">
        <part code="EC3_Elec_TR2_1">Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,</part>
        <iwer>Çava influencer la demande pour ce type de solution c'est ça ?</iwer>
        <part code="EC3_Elec_TR2_1">Je pense oui</part>
    </ver>
</corpus>"""

import xml.etree.ElementTree as ET
tree = ET.fromstring(xml_string)

for i in tree.findall('ver'):
    fmc = i.attrib.get("fmc")
    if fmc is None:
        continue
    for p in i.findall("part"):
        print(fmc, p.text)

输出是

motives Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.
condition Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.
obstacle Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,
obstacle Je pense oui

如果你想使用xpath表达式,你可以稍微简化一下

for i in tree.findall('ver[@fmc]'):
    for p in i.findall('part'):
        print(i.attrib['fmc'], p.text)

【讨论】:

    【解决方案2】:

    试试这个/fmc(.*?)+=(.*?)+\"(.+?)\"/g

    【讨论】:

      【解决方案3】:

      你可以试试正则表达式:

      <([a-zA-Z0-9]+)[^\/]*?fmc=([\'\"])(.*?)\2.*?>[\s\n\r]*<([a-zA-Z0-9]+).*?>(.*?)</\4>
      

      如所见here

      完整的代码如下所示:

      import re
      
      f = """<corpus>
          <ver id="18" etude="EC1_Elec" elec="oui" niveau="1" critere="1.3" type="discours">
              <part code="EC1_Elec_IW04_0">Ça existe sur des gros parcs Hlm mais c'est macro.</part>
          </ver>
          <ver id="30" etude="EC1_Elec" elec="oui" niveau="2" critere="" origine="IW" type="discours" fmc="motivation">
              <part code="EC1_Elec_IW01_0">Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.</part>
          </ver>
          <ver id="54" etude="EC1_Elec" elec="oui" niveau="1" critere="" origine="IW" type="discours" fmc="condition">
              <part code="EC1_Elec_IW10_0">Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.</part>
          </ver>
          <ver id="897" etude="EC3_Elec" elec="oui" niveau="4" critere="4.1" origine="TR" type="discours">
              <part code="EC3_Elec_TR2_1">Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,</part>
              <iwer>Çava influencer la demande pour ce type de solution c'est ça ?</iwer>
              <part code="EC3_Elec_TR2_1">Je pense oui</part>
          </ver>
      </corpus>"""
      
      regex = r'<([a-zA-Z0-9]+)[^\/]*?fmc=([\'\"])(.*?)\2.*?>[\s\n\r]*<([a-zA-Z0-9]+).*?>(.*?)</\4>'
      
      matches = re.findall(regex, f)
      
      for x in matches:
          print(x[2] + " " + x[4])
      

      【讨论】:

        【解决方案4】:

        正则表达式确实是错误的解决方案,但这可能有效:

        fmc="(.*?)".*?<part.*?>(.*?)</part>
        

        https://regex101.com/r/M7LJLU/1

        您想要的结果将在\1\2

        【讨论】:

        • 如果您有其他解决方案,请随时提出,我会尝试任何方法
        • @kely789456123 你似乎坚持使用正则表达式,所以我提供了一个可行的解决方案。如果您想要正确的解决方案,请查看xml.etree.ElementTree 并学习 XPath
        【解决方案5】:

        这是更适合 XML 解析器的工作。我使用来自PyPI 存储库的untangle

        import untangle
        
        xml = """<?xml version = "1.0" encoding="UTF-8" standalone="yes" ?>
        <corpus>
            <ver id="18" etude="EC1_Elec" elec="oui" niveau="1" critere="1.3" type="discours">
                <part code="EC1_Elec_IW04_0">Ça existe sur des gros parcs Hlm mais c'est macro.</part>
            </ver>
            <ver id="30" etude="EC1_Elec" elec="oui" niveau="2" critere="" origine="IW" type="discours" fmc="motives">
                <part code="EC1_Elec_IW01_0">Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.</part>
            </ver>
            <ver id="54" etude="EC1_Elec" elec="oui" niveau="1" critere="" origine="IW" type="discours" fmc="condition">
                <part code="EC1_Elec_IW10_0">Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.</part>
            </ver>
            <ver id="897" etude="EC3_Elec" elec="oui" niveau="4" critere="4.1" origine="TR" type="discours" fmc="obstacle">
                <part code="EC3_Elec_TR2_1">Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,</part>
                <iwer>Çava influencer la demande pour ce type de solution c'est ça ?</iwer>
                <part code="EC3_Elec_TR2_1">Je pense oui</part>
            </ver>
        </corpus>
        """
        
        doc = untangle.parse(xml)
        for ver in doc.corpus.ver:
            if ver['fmc'] is None: continue
            print(f"id={ver['id']}, fmc={ver['fmc']}")
            for part in ver.part:
                print(f"   part={part.cdata}")
        

        打印:

        id=30, fmc=motives
           part=Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.
        id=54, fmc=condition
           part=Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.
        id=897, fmc=obstacle
           part=Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,
           part=Je pense oui
        

        【讨论】:

        • 不是“de gros parcs”?喜欢“des petit pois”吗?
        • 谢谢,但我只想返回那些有 fmw 值而不是没有的
        • 很抱歉。那是一条线的变化。我已经更新了。
        【解决方案6】:

        您为什么不使用lxml 来解析您的XML?恕我直言,让 lxml 解析 xml 并使用例如导航生成的元素树要容易得多。 XPath 来找到你想要的东西。

        # install lxml
        pip3 install lxml
        
        # xml snippet
        xml = """\
        <?xml version = "1.0" encoding="UTF-8" standalone="yes" ?>
        <corpus>
            <ver id="18" etude="EC1_Elec" elec="oui" niveau="1" critere="1.3" type="discours">
                <part code="EC1_Elec_IW04_0">Ça existe sur des gros parcs Hlm mais c'est macro.</part>
            </ver>
            <ver id="30" etude="EC1_Elec" elec="oui" niveau="2" critere="" origine="IW" type="discours" fmc="motives">
                <part code="EC1_Elec_IW01_0">Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.</part>
            </ver>
            <ver id="54" etude="EC1_Elec" elec="oui" niveau="1" critere="" origine="IW" type="discours" fmc="condition">
                <part code="EC1_Elec_IW10_0">Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.</part>
            </ver>
            <ver id="897" etude="EC3_Elec" elec="oui" niveau="4" critere="4.1" origine="TR" type="discours" fmc="obstacle">
                <part code="EC3_Elec_TR2_1">Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,</part>
                <iwer>Çava influencer la demande pour ce type de solution c'est ça ?</iwer>
                <part code="EC3_Elec_TR2_1">Je pense oui</part>
            </ver>
        </corpus>
        """
        

        那么这就是解决问题的代码!

        # use lxml...
        from lxml import etree
        # parse the xml snippet into an object tree
        tree = etree.fromstring(bytes(xml, encoding='utf-8'))
        # find all elements that have "fmc" attribute
        for e in tree.findall(".//*[@fmc]"):
            label = e.xpath("./@fmc")[0]
            for c in e.findall("./part"):
                # print value of "fmc" attribute and text of all <part> elements
                print(f"{label:15}{c.text}")
        

        输出:

        motives        Avant 75 on n'a pas isolé puis après, au fur et à mesure des règlementations.
        condition      Le deuxième boitier, il est où ? s'il y en a un qui est à l'intérieur et qui remplace un bout de l'isolation, il est caché OK.
        obstacle       Avec l'économie d'énergie, on va imposer de plus en plus d'automatismes,
        obstacle       Je pense oui
        

        【讨论】:

        • 感谢您的建议。但我不希望 标签中的文本
        • 将答案更新为仅打印来自 元素的文本
        • 你好 {label:15} 对应什么我可以在函数中这样重写它:return label:15 否则它会是假的?
        • 它只是将空格填充到末尾,最多 15 个字符。你可以print(label, c.text)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-17
        相关资源
        最近更新 更多