Python XML按顺序解析子标记

时间:2017-08-05 14:07:40

标签: python xml python-3.x xml-parsing

我的XML文件类似于下面的文件:

<suite name="regression_1">
    <test name="Login check" id="s1-t1">
        <keyword name="Valid Username and Password">
            <keyword name="Invalid Username or Password">
                <keyword name="Invalid password">
                    <message level="TRACE" >Return error</message>
                    <status status="PASS"/>
                </keyword>
                <message level="INFO">Return error</message>
                <status status="FAIL"/>
            </keyword>
            <message level="INFO">Return: None</message>
            <status status="PASS"/>
        </keyword>
        <status status="FAIL"/>
    </test>
    <test name="test-2" id="s1-t1">
        <keyword name="abc">
            <keyword name="def">
                <message level="INFO">Return error</message>
                <status status="FAIL"/>
            </keyword>
            <message level="INFO">Return: None</message>
            <status status="PASS"/>
        </keyword>
        <status status="FAIL"/>
    </test>
</suite>

我的输出应检查关键字,并为状态为“FAIL”的人提供关键字结构。测试中会有很多关键字,可能有也可能没有子关键字。

****样本输出*******

套件:regression_1

测试名称:登录检查

关键字失败:[“有效用户名和密码”,“无效的用户名或密码”]

失败测试用例消息:返回错误

套件:regression_1

测试名称:test-2

关键字失败:[“abc”,“def”]

失败测试用例消息:返回错误

我的代码可以挖到最后一个孩子来收集失败状态。但是无法解析分析所需的正确路径。另外我认为完整的循环没有被执行。即如果第三个孩子是“通过”,则不会回到第二个孩子检查其状态。

def getStatusForNode(tc):
    status_to_be_returned = []
    is_just_father = False


    for child in tc.childNodes:
        if child.nodeName == "keyword":
            is_just_father = True
            status_to_be_returned.append(getStatusForNode(child)[0])
            keyword_track.append(child.getAttribute("name"))

    if not is_just_father:
        status = tc.getElementsByTagName('status')
        return [(tc, status)]


    return  status_to_be_returned


DOMTree = xml.dom.minidom.parse("output.xml")
collection = DOMTree.documentElement
tc_entry = collection.getElementsByTagName("suite")

top = Element('tests')
comment = Comment("This xml is generated only for failing tests")
top.append(comment)


for tc in tc_entry:
    if tc.hasAttribute("name"):
       print("Suite name: {}".format(tc.getAttribute("name")))

    tests = tc.getElementsByTagName('test')
    for test in tests:
        keyword_track = []
        for child in test.childNodes:
            if child.nodeName == "keyword":
                children_status = getStatusForNode(child)
                for (tc_name, status) in children_status:
                    for state in status:
                        if state.getAttribute("status") != "PASS":
                            print("---")
                            print("Test name: {}".format(test.getAttribute("name")))
                            print("Keyword failed: {}".format(tc_name.getAttribute("name")))
                            print("Status: {}".format(state.getAttribute("status")))
                            messages = tc_name.getElementsByTagName('msg')
                            print("Failure test case messages:")
                            for message in messages:
                                print(message.childNodes[0].data)
                            print ("")

从此代码收到的输出:

测试名称:ABC

关键字名称:keyword_1-2-3

状态:失败

失败测试用例消息:级别3失败

对代码的任何建议的优化?

1 个答案:

答案 0 :(得分:0)

  

问题:XML按顺序解析子标记

xml.etree.ElementTree的解决方案,例如:

  

注意<keyword>中的第一个Keyword faild:仍然没有意义,两者都有PASS。如果您想要输出中的第一个<keyword>,请删除#

from xml.etree import ElementTree as ET

with open('output.xml') as fh:
    suite = ET.fromstring(fh.read())

# Find all <test>"
for test in suite.findall('./test'):
    keyword_failed = []
    # first_keyword = test.find('./keyword')
    # keyword_failed = [first_keyword.attrib['name']]
    message = None

    # Find all <test><keyword> <status status="FAIL">
    for keyword in test.findall('.//keyword/status[@status="FAIL"]/..'):
        keyword_failed.append(keyword.attrib['name'])
        message = keyword.find('./message')

        print('Suite: {}'.format(suite.attrib['name']))
        print('\tTest Name: {}'.format(test.attrib['name']))
        print('\tKeyword failed: {}'.format(keyword_failed))
        print('\tFailure test case message : level={} {}'.format(message.attrib['level'], message.text))
  

<强>输出
      套房:regression_1
          测试名称:登录检查
          关键字失败:['无效的用户名或密码']
          故障测试用例消息:level = INFO返回错误
      套房:regression_1
          测试名称:test-2
          关键字失败:['def']
          失败测试用例消息:level = INFO返回错误

使用Python测试:3.4.2