Search code examples
pythonlxmlxml.etreeparse-tree

lxml - how to move elements into a folder based on a certain attribute


I have a KML that has a large number of placemarks, and 2 folders. How can I use etree to locate each placemark and move it into the corresponding folder. For example, the code should look for the element "SimpleData name='id'" and pick up 'Region 1', then move the whole Plaemark into the folder Area 1.

Before:

<Folder>
    <name>Cluster</name>
    <Folder>Area 1</Folder>
    <Folder>Area 2</Folder>
    <Placemark>
        <styleUrl>#falseColor9</styleUrl>
        <name>Customer 1</name>
        <ExtendedData>
            <SimpleData name="id">Region 1</SimpleData>
        </ExtendedData>
    </Placemark>
    <Placemark>
        <styleUrl>#falseColor8</styleUrl>
        <name>Customer 1</name>
        <ExtendedData>
            <SimpleData name="id">Region 2</SimpleData>
        </ExtendedData>
    </Placemark>    
</Folder>

After:

<Folder>
    <name>Cluster</name>
    <Folder>Area 1</Folder>
        <Placemark>
            <name>Customer 1</name>
            <styleUrl>#falseColor9</styleUrl>           
            <ExtendedData>
                <SimpleData name="id">Region 1</SimpleData>
            </ExtendedData>
        </Placemark>
    <Folder>Area 2</Folder>
        <Placemark>
            <styleUrl>#falseColor8</styleUrl>
            <name>Customer 1</name>
            <ExtendedData>
                <SimpleData name="id">Region 2</SimpleData>
            </ExtendedData>
        </Placemark>    
</Folder>

Any help would be much appreciated.


Solution

  • Using lxml, this can be done like this:

    from lxml import etree
    marks = """[your xml above]"""
    doc = etree.XML(marks.encode())
    for region in doc.xpath('//SimpleData'):
        target = region.text.split(' ')[1].strip()
        dests = doc.xpath('//Folder//Folder')
        for dest in dests:
            if target in dest.text:
                move =region.xpath('ancestor::Placemark')[0]
                dest.addnext((move))
    print(etree.tostring(doc).decode())
    

    Output:

    <Folder>
       <name>Cluster</name>
       <Folder>Area 1</Folder>
        <Placemark>
          <styleUrl>#falseColor9</styleUrl>
          <name>Customer 1</name>
          <ExtendedData>
             <SimpleData name="id">Region 1</SimpleData>
          </ExtendedData>
       </Placemark>
       
       <Folder>Area 2</Folder>
       <Placemark>
          <styleUrl>#falseColor8</styleUrl>
          <name>Customer 1</name>
          <ExtendedData>
             <SimpleData name="id">Region 2</SimpleData>
          </ExtendedData>
       </Placemark>
       </Folder>