decorate xml subtree with lxml
Question: I want to transform this xml tree

    
    
    <doc>
      <a>
        <op>xxx</op>
      </a>
    </doc>
    

to

    
    
    <doc>
      <a>
        <cls>
          <op>xxx</op>
        </cls>
      </a>
    </doc>
    

I use this python code

    
    
    from lxml import etree
    f = etree.fromstring('<doc><a><op>xxx</op></a></doc>')
    
    node_a = f.xpath('/doc/a')[0]
    ele = etree.Element('cls')
    node_a.insert(0, ele)
    
    node_cls = f.xpath('/doc/a/cls')[0]
    node_op = f.xpath('/doc/a/op')[0] 
    node_cls.append(node_op) 
    print etree.tostring(f, pretty_print=True)
    

Is it the best solution ?

Now I want to obtain

    
    
    <cls>
      <doc>
        <a>
          <op>xxx</op>    
        </a>
      </doc>
    </cls>
    

I am unable to find any solution.

Thanks for your help.


Answer: I prefer to use [beautifulsoup](/questions/tagged/beautifulsoup "show
questions tagged 'beautifulsoup'") better than [lxml](/questions/tagged/lxml
"show questions tagged 'lxml'"). I find it easier to handle.

Both problems can be solved using the same approach, first find the element,
get its parent, create the new element and put the old one inside it.

    
    
    from bs4 import BeautifulSoup
    import sys 
    
    soup = BeautifulSoup(open(sys.argv[1], 'r'), 'xml')
    for e in soup.find_all(sys.argv[2]):
        p = e.parent
        cls = soup.new_tag('cls')
        e_extracted = e.extract()
        cls.append(e_extracted)
        p.append(cls)
    
    print(soup.prettify())
    

The script accepts two arguments, thr first one is the `xml` file and second
one the tag to surround with new tag. Run it like:

    
    
    python3 script.py xmlfile op
    

That yields:

    
    
    <?xml version="1.0" encoding="utf-8"?>
    <doc>
     <a>
      <cls>
       <op>
        xxx
       </op>
      </cls>
     </a>
    </doc>
    

For `<doc>`, run it like:

    
    
    python3 script.py xmlfile doc
    

With following result:

    
    
    <?xml version="1.0" encoding="utf-8"?>
    <cls>
     <doc>
      <a>
       <op>
        xxx
       </op>
      </a>
     </doc>
    </cls>
    

