从 XML 中提取的 Python 保持相同的模式



我有一个具有以下架构的XML:

<?xml version="1.0" encoding="utf-8" ?>
<ROOT>
<facturic id_user="18446195"><artfacturic/></facturic>
<facturic id_user="18446195"><artfacturic/></facturic>
<facturic id_user="34259554"><artfacturic/></facturic>
</ROOT>

它们的属性比id_user多得多,但只有那个属性是相关的,因为我需要将 xml 文件拆分为存在重复 ID 的单独文件。

我设法使用以下代码找到了重复项:

import os
from xml.etree import ElementTree
dom = ElementTree.parse(fullpath)
findNode = 'facturic'
findAttr = 'id_user'
childNodes = dom.findall(findNode)
userIdDict = dict()     #student={'name':'john','age':23}
duplicateUserId = dict()
#GET UNIQUE USER ID AND COUNT
for c in childNodes:
    userId = c.attrib.get(findAttr)  #gets attributes
    #print(nrFact)
    if userId not in userIdDict:
        userIdDict[userId] = 1
    else:
        userIdDict[userId] = userIdDict[userId] + 1
# print(userIdDict)
for userId in userIdDict:
    userIdCount = userIdDict[userId]
    if userIdCount > 1:
        duplicateUserId[userId]=userIdCount

你们能给我一个想法,如何创建新的xml文件,只包含重复的节点,但使用与初始文件相同的架构?它应该类似于为每个重复节点创建新的 xml 文件,或者理想情况下,假设重复用户 ID 的最大数量为 4,只创建 4 个文件,但每个文件应仅包含具有所有其他初始属性的唯一 ID。

我会做这样的事情:使用defaultdict(list)收集每个id_user值的节点。然后,对生成的字典进行后处理,将重复项写入单独的文件。使用lxml.etree

from collections import defaultdict
from lxml import etree
tree = etree.parse("input.xml")
facturics = defaultdict(list)
for node in tree.xpath(".//facturic"):
    facturics[node.attrib["id_user"]].append(node)
for user_id, nodes in facturics.items():
    if len(nodes) > 1:  # save duplicates
        with open("{user_id}.xml".format(user_id=user_id), "w") as output_file:
            root = etree.Element("ROOT")
            for node in nodes:
                root.append(node)
            etree.ElementTree(root).write(output_file, pretty_print=True)

运行此代码后,当前目录中会生成一个名为 18446195.xml 的新文件,内容如下:

<ROOT>
    <facturic id_user="18446195"><artfacturic/></facturic>
    <facturic id_user="18446195"><artfacturic/></facturic>
</ROOT>

考虑 XSLT,这是一种专用语言,旨在转换 XML,例如保留具有重复属性的节点。Python的第三方模块lxml可以运行XSLT 1.0脚本。美妙之处在于XSLT可以移植到其他语言/软件,并且不需要Python来运行它!

具体来说,下面使用慕尼黑分组来索引文档,其中包含每个不同@id_userxsl:key。然后,模板匹配仅检索计数大于 1 的那些。

XSLT (另存为 .xsl 文件,一个特殊的.xml文件(

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>
  <xsl:key name="idkey" match="facturic" use="@id_user" />
  <xsl:template match="/ROOT">
    <xsl:copy>
      <xsl:apply-templates select="facturic"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="facturic[count(key('idkey', @id_user)) > 1]">
    <xsl:copy>
        <xsl:copy-of select="*|@*"/>    
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Python(没有for循环或if逻辑(

import lxml.etree as et
# LOAD XML AND XSL FILES
doc = et.parse('Input.xml')
xsl = et.parse('XSLTScript.xsl')
# INITIALIZE TRANSFORMER AND RUN
transform = et.XSLT(xsl)    
result = transform(doc)
# PRINT TO CONSOLE
print(result)
# SAVE TO FILE
with open('Output.xml', 'wb') as f:
   f.write(result)

输出

<?xml version="1.0"?>
<ROOT>
  <facturic id_user="18446195">
    <artfacturic/>
  </facturic>
  <facturic id_user="18446195">
    <artfacturic/>
  </facturic>
</ROOT>

最新更新