使用类似的父节点xml,python合并子节点

时间:2014-03-31 16:46:50

标签: python xml

我有以下xml文件:

<root>
    <article_date>09/09/2013
    <article_time>1
        <article_name>aaa1</article_name>
        <article_link>1aaaaaaa</article_link>
    </article_time>
    <article_time>0
        <article_name>aaa2</article_name>
        <article_link>2aaaaaaa</article_link>
    </article_time>
    <article_time>1
        <article_name>aaa3</article_name>
        <article_link>3aaaaaaa</article_link>
    </article_time>
    <article_time>0
        <article_name>aaa4</article_name>
        <article_link>4aaaaaaa</article_link>
    </article_time>
    <article_time>1
        <article_name>aaa5</article_name>
        <article_link>5aaaaaaa</article_link>
    </article_time>
    </article_date>
</root>

我想将其转换为以下文件:

<root>
    <article_date>09/09/2013
    <article_time>1
        <article_name>aaa1+aaa3+aaa5</article_name>
        <article_link>1aaaaaaa+3aaaaaaa+5aaaaaaa</article_link>
    </article_time>
    <article_time>0
        <article_name>aaa2+aaa4</article_name>
        <article_link>2aaaaaaa+4aaaaaaa</article_link>
    </article_time>
</root>

我怎么能在python中做到这一点?

我执行此任务的方法如下: 1)循环标记 2)表单字典键 - 0或1,值 - 3)对于该字典中的每个元素,找到所有子节点:并附加它们

从那以后,我编写了以下代码来实现这个(ps我目前正在努力为字典添加元素,但我会克服这个问题):

def parse():
list_of_inique_timestamps=[]
text_to_merge=""
tree=et.parse("~/Documents/test1.xml")
root=tree.getroot()
for children in root:
    print children.tag, children.text
    for child in children:
        print (child.tag,int(child.text))
        if not child.text in list_of_inique_timestamps:
            list_of_inique_timestamps.append(child.text)
print list_of_inique_timestamps

2 个答案:

答案 0 :(得分:2)

以下是使用python标准库中的xml.etree.ElementTree的解决方案。

我们的想法是将项目收集到defaultdict(list)article_time个文字值:

from collections import defaultdict
import xml.etree.ElementTree as ET

data = """<root>
    <article_date>09/09/2013
    <article_time>1
        <article_name>aaa1</article_name>
        <article_link>1aaaaaaa</article_link>
    </article_time>
    <article_time>0
        <article_name>aaa2</article_name>
        <article_link>2aaaaaaa</article_link>
    </article_time>
    <article_time>1
        <article_name>aaa3</article_name>
        <article_link>3aaaaaaa</article_link>
    </article_time>
    <article_time>0
        <article_name>aaa4</article_name>
        <article_link>4aaaaaaa</article_link>
    </article_time>
    <article_time>1
        <article_name>aaa5</article_name>
        <article_link>5aaaaaaa</article_link>
    </article_time>
    </article_date>
</root>
"""

tree = ET.fromstring(data)

root = ET.Element('root')
article_date = ET.SubElement(root, 'article_date')
article_date.text = tree.find('.//article_date').text

data = defaultdict(list)
for article_time in tree.findall('.//article_time'):
    text = article_time.text.strip()
    name = article_time.find('./article_name').text
    link = article_time.find('./article_link').text
    data[text].append((name, link))

for time_value, items in data.iteritems():
    article_time = ET.SubElement(article_date, 'article_time')
    article_name = ET.SubElement(article_time, 'article_name')
    article_link = ET.SubElement(article_time, 'article_name')

    article_time.text = time_value
    article_name.text = '+'.join(name for (name, _) in items)
    article_link.text = '+'.join(link for (_, link) in items)

print ET.tostring(root)

打印(美化):

<root>
    <article_date>09/09/2013
        <article_time>1
            <article_name>aaa1+aaa3+aaa5</article_name>
            <article_name>1aaaaaaa+3aaaaaaa+5aaaaaaa</article_name>
        </article_time>
        <article_time>0
            <article_name>aaa2+aaa4</article_name>
            <article_name>2aaaaaaa+4aaaaaaa</article_name>
        </article_time>
    </article_date>
</root>

看,结果正是你的目标。

答案 1 :(得分:1)

我会尽可能多地写下时间(和知识),但我会将其作为社区维基,以便其他人可以提供帮助。

我建议您使用xmlBeautifulSoup库。我将使用BeautifulSoup,因为我现在无法让xml工作。

首先,让我们进行设置:

>>> import bs4
>>> soup = bs4.BeautifulSoup('''<root>
...     <article_date>09/09/2013
...     <article_time>1
...         <article_name>aaa1</article_name>
...         <article_link>1aaaaaaa</article_link>
...     </article_time>
...     <article_time>0
...         <article_name>aaa2</article_name>
...         <article_link>2aaaaaaa</article_link>
...     </article_time>
...     <article_time>1
...         <article_name>aaa3</article_name>
...         <article_link>3aaaaaaa</article_link>
...     </article_time>
...     <article_time>0
...         <article_name>aaa4</article_name>
...         <article_link>4aaaaaaa</article_link>
...     </article_time>
...     <article_time>1
...         <article_name>aaa5</article_name>
...         <article_link>5aaaaaaa</article_link>
...     </article_time>
... </root>''')

这只是生成xml的内部表示。我们可以使用find_all方法来抓取所有文章时间。

>>> children = soup.find_all('article_time')
>>> children
[<article_time>1
        <article_name>aaa1</article_name>
<article_link>1aaaaaaa</article_link>
</article_time>, <article_time>0
        <article_name>aaa2</article_name>
<article_link>2aaaaaaa</article_link>
</article_time>, <article_time>1
        <article_name>aaa3</article_name>
<article_link>3aaaaaaa</article_link>
</article_time>, <article_time>0
        <article_name>aaa4</article_name>
<article_link>4aaaaaaa</article_link>
</article_time>, <article_time>1
        <article_name>aaa5</article_name>
<article_link>5aaaaaaa</article_link>
</article_time>]

接下来要做的是定义一个关键,以便我们定义类似的&#39;父节点。让我们编写一个key函数,指定要查看每个子项的哪个部分。我们先做一些事情来了解每个孩子的结构。

>>> children[0].contents
[u'1\n        ', <article_name>aaa1</article_name>, u'\n', <article_link>1aaaaaaa</article_link>, u'\n']
>>> children[0].contents[0]
u'1\n        '
>>> int(children[0].contents[0])
1
>>> def key(child):
...     return int(child.contents[0])
...
>>> key(children[0])
1
>>> key(children[1])
0

好。现在我们可以利用python的itertools.groupby函数,它将所有具有相同键的子组合在一起(我们需要先排序)。我们将使用新定义的key函数来指定如何排序以及定义组的内容。

>>> children = sorted(children, key=key)
>>> import itertools
>>> groups = itertools.groupby(children, key)

groups是一个生成器 - 就像一个列表,但我们只能迭代一次。让我们来看看它是什么构成的,即使这意味着我们必须在以后重新创建它。 (我们只为生成器获得一次通过,因此通过查看数据,我们会丢失它。幸运的是,它很容易重新创建)

>>> for k, g in groups:
...     print k, ':\t', list(g)
...
0 : [<article_time>0
        <article_name>aaa2</article_name>
<article_link>2aaaaaaa</article_link>
</article_time>, <article_time>0
        <article_name>aaa4</article_name>
<article_link>4aaaaaaa</article_link>
</article_time>]
1 : [<article_time>1
        <article_name>aaa1</article_name>
<article_link>1aaaaaaa</article_link>
</article_time>, <article_time>1
        <article_name>aaa3</article_name>
<article_link>3aaaaaaa</article_link>
</article_time>, <article_time>1
        <article_name>aaa5</article_name>
<article_link>5aaaaaaa</article_link>
</article_time>]

好的,k指定用于生成群组的密钥,g是与article_time匹配的k的序列。

对不起,我现在有时间。希望这足以让你开始。