简体   繁体   中英

Removing and replacing specific nodes in an XML file

I have been working on a project that analyses a musical score and removes specific notes from it. So now that I have the information required from my code I now need to edit the original XML score with my new information. I am doing this in Python and have already used Minidom so I would obviously like to stick to that (I know this was perhaps a silly choice as a lot of the posts on here recommend different methods of XML parsing due to the not so friendly interface present in Minidom).

So say in my original XML file I have a musical piece made up of just 10 notes. The XML format for a note is shown below:

<note>
  <pitch>
    <step>E</step>
    <alter>-1</alter>
    <octave>5</octave>
  </pitch>
  <duration>72</duration>
</note>

So this would be repeated 10 times for each note value. Now that I have done my analysis I want to remove 5 of these notes. By remove I mean replace with a rest (as it is a musical score after all and it has a shape to conform to). So the format for a rest in an XML file is shown below:

<note>
    <rest/>
    <duration>72</duration>
</note>

So all that I have to do is remove the pitch tag and replace it with a rest tag. However I am unsure on how to go about this, haven't really found anything from my searching that seems similar.

I am not too bothered about finding where the notes to be removed are, as I have written a quick test harness to show how I would go about that below in Python (xml_format is essentially just a list of dictionaries containing my new information). It contains the same number of notes as the original XML file, with the only difference being that some of them are now marked for being removed. So the original file could have notes like : G, Bb, D, C, G, F, G, D, Bb and the xml_format would have G, Bb, D, REMOVE, G, REMOVE, G, D, Bb etc.

I have just returned a at the moment to make sure that the correct number of notes are being removed.

def remove_notes(xml_format, filename):

doc = minidom.parse(filename)                 
count = 0
a = 0
note = doc.getElementsByTagName("note")  

for item in note:
    if xml_format[count]['step'] == 'Remove':
        a = a + 1
        # THEN REMOVE THE ENTIRE PITCH TAG, REPLACE WITH REST
    count = count + 1
    # ELSE DON'T DO ANYTHING

return a 

So basically I am just looking for some assistance in the kind of syntax or code that could be used to remove a specific node at a specific point and then be replaced with a new node, before being written to a new file. Thank you very much for any help and I do hope that this is something which is possible (the logic doesn't seem complicated, but who knows what is possible)!

What you need to do for every <note> node is:

  1. Create a new <rest/> node
  2. Locate the <pitch> node
  3. Replace the <pitch> node with the new <rest/> node

Here is the code:

def remove_notes(xml_format, filename):
    doc = minidom.parse(filename)                 
    count = 0
    a = 0
    note_nodes = doc.getElementsByTagName("note")  

    for note_node in note_nodes:
        if xml_format[count]['step'] == 'Remove':
            a = a + 1

            # Create a <rest/> node
            rest_node = note_node.ownerDocument.createElement('rest')

            # Locate the <pitch> node
            pitch_node = note_node.getElementsByTagName('pitch')[0]

            # Replace pitch with rest
            note_node.replaceChild(rest_node, pitch_node)

        count = count + 1
        # ELSE DON'T DO ANYTHING

    # Finished with the loop, doc now contains the replaced nodes, we need
    # to write it to a file    

    return a 

Please note that you will need to write the changes to a new file or your changes will be lost.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM