【问题标题】:Python and ElementTree: How can I nest elements/subelements in an XML?Python 和 ElementTree:如何在 XML 中嵌套元素/子元素?
【发布时间】:2015-05-05 20:33:01
【问题描述】:

背景

我正在使用 Python 2.6ElementTreeSQLite3。我的脚本目前执行以下操作:

  • 连接到数据库以从表/模式中检索信息
  • 将必要的数据添加到 XML 树中
  • 输出一个(当前不正确的)XML 文件

代码

这是我检索架构数据并向 XML 添加元素的方式。我对SOFTWARE_TARGET_ 表执行此操作。这是SOFTWARE_ 表:

software_attributes =  ["id", "functionalDesignationHardware", "hwfin", "identname", "partnumber",
                        "repfin", "targetHardwareID"]

software = db.cursor().execute("SELECT %s from SOFTWARE_" % ", ".join([i + "_" for i in software_attributes]))
software_Data = software.fetchall()
ID1 = db.cursor().execute("SELECT id_ from SOFTWARE_")
software_IDs = ID1.fetchall()

for sw in software_Data:
   sw_node = ET.SubElement(root, "Software")
   for s in range(1, len(software_attributes)):
      sw_node.set(software_attributes[s], str(sw[s]))

更新:这是我的 TARGET_ 表代码:

target_attributes = ["id", "functionalDesignationSoftware", "installscriptpathname", "ata", "status",
                     "swfin", "targetOSFC", "timestamp"]

target = db.cursor().execute("SELECT %s from TARGET_" % ", ".join([i + "_" for i in target_attributes]))
target_Data = target.fetchall()
ID2 = db.cursor().execute("SELECT id_ from TARGET_")
target_IDs = ID2.fetchall()

## CURRENTLY INCORRECT - only adds to the last created Software Element ##
for tg in target_Data:
   tg_node = ET.SubElement(sw_node, "TargetModule")
   for t in range(1, len(target_attributes)):
      tg_node.set(target_attributes[t], str(tg[t]))

这就是我从表中存储信息的方式,这些表的唯一目的是连接 other 表中的数据。 SOFTWARE_TARGET_ 表将SOFTWARE_ 连接到TARGET_。我将其信息存储在字典中:

software_target = db.cursor().execute("SELECT SOFTWARE1, TARGET2 from SOFTWARE_TARGET_")
software_target_Data = software_target.fetchall()

# Map SOFTWARE1 to TARGET2
separated_st_Data = {}
for item in software_target_Data:
    software1, target2 = item
    try:
        separated_st_Data[software1].append(target2)
    except KeyError:
        separated_st_Data[software1] = [target2]

尝试

到目前为止,我已经弄清楚了如何设置我的 xml 格式:

<Software attribute="stuff" attribute2="Stuff"/>
<Software attribute="stuff" attribute2="Stuff"/>
<Target attribute="things" attribute2="Things"/>

但我需要的是以下格式:

<Software attribute="stuff" attribute2="Stuff"
    <Target attribute="things" attribute2="Things"/>
    <Target attribute="things" attribute2="Things"/>
</Software>
<Software attribute="stuff" attribute2="Stuff"/>

哪个Target 子元素在哪个Software 元素之下由SOFTWARE_TARGET_ 表中的信息确定。我找到了如何遍历我的字典,如下所示:

depth=0
for k,v in sorted(separated_st_Data.items(),key=lambda x: x[0]):
    if isinstance(v, dict):
        print ("  ")*depth + ("%s" % k)
        walk_dict(v,depth+1)
    else:
        print ("  ")*depth + "%s %s" % (k, v)

问题

如何根据数据库表中的信息创建格式正确的 XML 文件(如 Attemps 部分所述)?我创建了字典,认为我可以将它用于此目的 - 如果有必要,请告诉我。


备注

This 是我从SOFTWARE_TARGET_ 表创建的字典的样子。键表示来自SOFTWARE_id_ 架构,值表示来自TARGET_id_ 架构。 (如果我的术语听起来不对劲,请告诉我——数据库有时会让我感到困惑)。

【问题讨论】:

    标签: python xml dictionary python-2.6 elementtree


    【解决方案1】:

    在创建 Target 元素(此处的问题中未给出代码)时,请确保将它们要附加到的 sw_node 作为第一个参数传递。

    即:

    target_el = SubElement(sw_node, "Target")
    

    而不是...

    target_el = SubElement(root_node, "Target")
    

    此类代码的典型模式可能具有以下外观(大致;需要一些测试,使用 pyformat 参数样式为 DB-API 驱动程序编写,并且不能与其他代码一起使用):

    cursor = db.cursor()
    cursor.execute("SELECT * from SOFTWARE_")
    for sw_item in cursor.fetchall():
      sw_el = SubElement(root_el, 'Software') ## STORING THE ELEMENT HERE
      sw_id = None
      for idx in range(len(cursor.description)):
        name = cursor.description[idx][0]
        if name == 'id':
          sw_id = sw_item[idx]
        sw_el.attrib[name] = sw_item[idx]
      ## QUERYING FOR CHILDREN HERE
      cursor.execute("SELECT TARGET_.*
                      FROM TARGET_, SOFTWARE_TARGET_
                      WHERE SOFTWARE_TARGET_.SOFTWARE1=%(sw_id)s
                        AND SOFTWARE_TARGET_.TARGET2=TARGET_.ID",
          sw_id=sw_id)
      for target_item in cursor.fetchall():
        # create a new target element
        target_el = SubElement(sw_el, 'Target')
        # assign attributes to that element
        for idx in range(len(cursor.description)):
          name = cursor.description[idx][0].rsplit('.', 1)[-1]
          target_el.attrib[name] = target_item[idx]
    

    【讨论】:

    • 感谢您的回答。我一般了解如何添加子元素-我的问题是我不确定如何根据链接两者的SOFTWARE_TARGET 表中提供的信息将某些Target 元素添加到它们各自的Software 元素中(不是所有的Software 元素都会有一个Target 子元素,而有些会有多个Target 子元素)。这有意义吗?
    • 我不确定我是否在这里了解了您的所有代码。当您处理每个 Software 元素(因此手头有指向该元素的指针)时,您是否有理由不查询关联的 Target 元素并对其进行迭代?或者,如果您只执行一次连接来创建封装该数据的结构,则对结构的索引应该是微不足道的。
    • 我已经更新了我的问题。我不确定我是否完全理解您的建议 - 您能否提供一个链接让我可以考虑这样做?
    • 我添加了一些显示该模式的伪代码。凭记忆写的,需要一些调试,但显示了一般机制。
    • 我收到以下错误:for idx in range(cursor.description): TypeError: range() integer end argument expected, got tuple.
    【解决方案2】:

    糟糕,差点忘了 - 这是我最终在完成的 Python 脚本中使用的最终代码(当然,要减去完整脚本的一些关键元素):

    software_attributes =  ["id", "partnumber", "identname", "functionalDesignationHardware", "hwfin", 
                            "targetHardwareID","repfin", "amendment"]
    
    target_attributes = ["id", "swfin", "targetOSFC", "functionalDesignationSoftware", "installscriptpathname", 
                         "ata", "status","timestamp"]
    
    sw_current = cursor.execute("SELECT %s from SOFTWARE_" % ", ".join([i + "_" for i in software_attributes]))
    sw_current = sw_current.fetchall()
    for sw_item in sw_current:
        current_sw_ID = sw_item[0]
    
        # Create Software XML Element
        sw_element = ET.SubElement(root, "Software")
        # Set Software attributes
        for s in range(1, len(software_attributes)):
            sw_element.set(software_attributes[s], str(sw_item[s]))
    
        # Get all Target IDs for current Software Element
        current_tg_IDs = cursor.execute("SELECT TARGET2 from SOFTWARE_TARGET_ WHERE SOFTWARE1=?", (current_sw_ID,))
        current_tg_IDs = list(chain.from_iterable(current_tg_IDs.fetchall()))
        while len(current_tg_IDs) > 0:
            tg_id = current_tg_IDs.pop(0)
            tg_current = cursor.execute("SELECT %s from TARGET_ WHERE id_=?" % ", ".join([i + "_" for i in target_attributes]), (str(tg_id).strip('[]'),))
            tg_current = tg_current.fetchall()
    
            for tg_item in tg_current:
                # Create Target XML Element
                tg_element = ET.SubElement(sw_element, "TargetModule")
                # Set Target attributes
                for t in range(1, len(target_attributes)):
                    tg_element.set(target_attributes[t], str(tg_item[t]))
    

    注意:在我上面的最后一次尝试中,我没有最终使用这个问题中最初假设的字典方法 - 我的最终方法对我的目的更有效。有关使用字典的方法示例,请参阅此问题的选定答案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-15
      • 1970-01-01
      • 2013-02-17
      • 2018-08-27
      • 2023-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多