【问题标题】:Python: How to Loop thoough every XML node and print values based on listPython:如何循环每个 XML 节点并根据列表打印值
【发布时间】:2018-02-13 18:19:17
【问题描述】:

出于验证目的:如何逐个节点(甚至是子节点)搜索整个 XML 节点,如下所示:

XML 文件:

<Summary>
<Hardware_Info>
    <HardwareType>FlashDrive</HardwareType>
    <ManufacturerDetail>
            <ManufacturerCompany>Company1</ManufacturerCompany>
            <ManufacturerDate>2017-07-20T12:26:04-04:00</ManufacturerDate>
            <ModelCode>4BR6282</ModelCode>
    </ManufacturerDetail>
    <ActivationDate>2017-07-20T12:26:04-04:00</ActivationDate>
</Hardware_Info>
<DeviceConnectionInfo>
    <Device>
        <Index>0</Index>
        <Name>Laptop1</Name>
        <Status>Installed</Status>
    </Device>
    <Device>
        <Index>1</Index>
        <Name>Laptop2</Name>
        <Status>Installed</Status>
    </Device>
</DeviceConnectionInfo>
</Summary>

并根据特定表的匹配列搜索值。举例来说,表格是这样的:

表格:

HardwareType    ManufacturerCompany    ManufacturerDate             ActivationDate              Device.Index        Name
FlashDrive      Company1               2017-07-20T12:26:04-04:00    2017-07-20T12:26:04-04:00   0                   Laptop1
FlashDrive      Company2               2017-07-20T12:26:04-04:00    2017-07-20T12:26:04-04:00   1                   Laptop2

在这种情况下,我将有一个列列表:

HardwareType, ManufacturerCompany, ManufacturerDate, ActivationDate, Device.Index, Name

对于我的最终结果,我想打印表列名的值以及在 xml 中找到的表名的值。例如类似于原始表(假设验证很好):

输出结果:

 HardwareType   ManufacturerCompany    ManufacturerDate             ActivationDate              Device.Index        Name
    FlashDrive      Company1               2017-07-20T12:26:04-04:00    2017-07-20T12:26:04-04:00   0                   Laptop1
    FlashDrive      Company2               2017-07-20T12:26:04-04:00    2017-07-20T12:26:04-04:00   1                   Laptop2

当前实现:

例如,我可以获取表的列名列表,但是到目前为止,我的知识最好的实现方法是:

import xml.etree.ElementTree as ET
import csv

tree = ET.parse("/test.xml")
root = tree.getroot()

f = open('/test.csv', 'w')

csvwriter = csv.writer(f)

count = 0

head = ['ManufacturerCompany','ManufacturerDate',...]

csvwriter.writerow(head)

for time in root.findall('Summary'):
     row = []
     job_name = time.find('ManufacturerDetail').find('ManufacturerCompany').text
     row.append(job_name)
     job_name = time.find('ManufacturerDetail').find('ManufacturerDate').text
     row.append(job_name)
     csvwriter.writerow(row)
f.close()

但是,这个实现没有循环输出我想要的每个功能。任何有关实施的指导或建议都会很棒。

谢谢

【问题讨论】:

    标签: python xml parsing elementtree


    【解决方案1】:

    考虑XSLT,这是一种专用语言,旨在将 XML 文件转换为其他 XML、HTML(主要用于)以及文本文件 (TXT/CSV),其 method="text"。具体来说,向下走到 Device 节点级别并带来祖先项目。

    Python 的第三方lxml 模块可以运行XSLT 1.0 脚本。但是,XSLT 是可移植的,any XSLT processor 可以运行此类代码,包括可用的 Unix (Linux/Mac) xsltproc

    XSLT (另存为.xsl文件,特殊的.xml文件;&amp;#xa;是换行实体)

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output indent="yes" method="text"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:param name="delimiter">,</xsl:param>
    
      <xsl:template match="/Summary">
        <xsl:text>HardwareType,ManufacturerCompany,ManufacturerDate,ActivationDate,Device.Index,Name&#xa;</xsl:text>    
        <xsl:apply-templates select="DeviceConnectionInfo"/>    
      </xsl:template>
    
      <xsl:template match="DeviceConnectionInfo">
        <xsl:apply-templates select="Device"/>    
      </xsl:template>
    
      <xsl:template match="Device">
        <xsl:value-of select="concat(ancestor::Summary/Hardware_Info/HardwareType, $delimiter,
                                     ancestor::Summary/Hardware_Info/ManufacturerDetail/ManufacturerCompany, $delimiter,
                                     ancestor::Summary/Hardware_Info/ManufacturerDetail/ManufacturerDate, $delimiter,
                                     ancestor::Summary/Hardware_Info/ActivationDate, $delimiter,
                                     Index, $delimiter,
                                     Name)"/><xsl:text>&#xa;</xsl:text>
      </xsl:template>
    
    </xsl:stylesheet>
    

    Python (使用 lxml)

    import lxml.etree as et
    
    # LOAD XML AND XSL
    doc = et.parse('input.xml')
    xsl = et.parse('xslt_script.xsl')
    
    # TRANSFORM INPUT TO STRING
    transform = et.XSLT(xsl)    
    result = str(transform(doc))
    
    # SAVE TO FILE
    with open('output.csv', 'w') as f:
        f.write(result)
    

    Python (对 xsltproc 的单行命令调用)

    from subprocess import Popen
    
    proc = Popen(['xsltproc -o output.csv xslt_script.xsl input.xml'], 
                 shell=True, cwd='/path/to/working/directory')
    

    输出

    # HardwareType  ManufacturerCompany ManufacturerDate    ActivationDate  Device.Index    Name
    # FlashDrive    Company1    2017-07-20T12:26:04-04:00   2017-07-20T12:26:04-04:00   0   Laptop1
    # FlashDrive    Company1    2017-07-20T12:26:04-04:00   2017-07-20T12:26:04-04:00   1   Laptop2
    

    【讨论】:

    • @Pairfait,感谢您的意见,我会尽快试一试!
    • @Techno04335 ... 试用情况如何?
    • @Pairfait ,我想澄清一下我的理解,根据我拥有的列列表,我是否在 XLST 文件中输入了它?这个过程在哪个过程中根据列名打印/输出元素值?
    • 不需要列列表。您在 XSLT 脚本中列出标题,请参阅 &lt;xsl:text&gt;...&lt;/xsl:text&gt;,然后另一个模板运行 XPath 搜索以查找那些需要的值。
    • @Pairfait,我得到了工作的建议!感谢你的协助!我希望您能根据我要查找的值对 XSLT 文件进行自动化处理。谢谢。
    猜你喜欢
    • 2021-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-06
    • 2021-08-13
    • 1970-01-01
    • 2018-02-05
    • 2018-05-31
    相关资源
    最近更新 更多