How to search for a child key in an xml and pass it to another parent with Python/bs4?
Question: Here is a sample of the xml I am working with:

    
    
    <bare>
        <key name="plus.root" value="/apps/mobile/plus"/>
        <key name="local.root" value="/apps/net/plus"/>
        <key name="slack.messaging.root" value="/apps/root/docs"/>
    </bare>>
    <app name="social">
        <key name="social.password" value="secret">
        <key name="user" value = "secret">
    </app>
    <app name="plus">
        <key name="user" value = "secret">
    </app>
    

I am trying to look through each key under "bare" and if the first word
matches an app name, move the key/value under the app key (as child). So for
example, plus.root would be removed from the bare section and added under the
"app name=plus section". If the app name does not exist, the key should be
left alone under the bare section.

Currently my code looks like this, but I'm having trouble figuring out
properly do this.

    
    
    from bs4 import BeautifulSoup, Tag
    
    soup = BeautifulSoup(data, "xml")
    
    apps = soup.find("app")
    bare = soup.root.bare
    
    # loop over all the "key's under "bare"
    for key in bare.find_all("key"):
        app_name = key["name"].split(".")[0]
    
        # find apps that match name of the bare key
        app = apps.find("app", {"name": app_name})
    
        #if we find any, ???append the key to the app???? then remove the key from the bare section
        if app:
            key = key.extract()
            app.append(key)
            # remove "bare"
            bare.extract()
    
    print(soup.prettify())
    

Is there a better way to do this?


Answer: Here is a working sample to get you started. Here we are moving all of the
keys under the "bare" to under a separate "apps" tag, grouping by app name:

    
    
    from bs4 import BeautifulSoup, Tag
    
    data = """
    <root>
        <bare>
            <key name="plus.root" value="/apps/mobile/plus"/>
            <key name="local.root" value="/apps/net/plus"/>
            <key name="slack.messaging.root" value="/apps/root/docs"/>
        </bare>
        <apps/>
    </root>
    """
    soup = BeautifulSoup(data, "xml")
    
    apps = soup.find("apps")
    bare = soup.root.bare
    # loop over all the "key"s under "bare"
    for key in bare.find_all("key"):
        app_name = key["name"].split(".")[0]
    
        # find app and create if not exists
        app = apps.find("app", {"name": app_name})
        if not app:
            app = soup.new_tag("app")
            app.attrs["name"] = app_name
            apps.append(app)
    
        # remove the key from "bare" and append to a specific app
        key = key.extract()
        app.append(key)
    
    # remove "bare"
    bare.extract()
    
    print(soup.prettify())
    

Here is the result:

    
    
    <?xml version="1.0" encoding="utf-8"?>
    <root>
     <apps>
      <app name="plus">
       <key name="plus.root" value="/apps/mobile/plus"/>
      </app>
      <app name="local">
       <key name="local.root" value="/apps/net/plus"/>
      </app>
      <app name="slack">
       <key name="slack.messaging.root" value="/apps/root/docs"/>
      </app>
     </apps>
    </root>
    

