Python bs4 removes br tag
Question: I use bs4 to manipulate some rich-text. but it removes br tag inside where i
did character conversion. below is the simple form of the code.

    
    
    import re
    from bs4 import BeautifulSoup
    
    #source_code = self.textInput.toHtml()
    source_code =  """.......<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">ABC ABC<br />ABC</span></p>.......""" 
    
    soup = BeautifulSoup(source_code, "lxml")
    
    for elm in soup.find_all('span', style=re.compile(r"font-family:'Ubuntu'")):
    #actually there was a for loop
        elm.string = elm.text.replace("A", "X")
        elm.string = elm.text.replace("B", "Y")
        elm.string = elm.text.replace("C", "Z")
    
    print(soup.prettify())
    

this should give an output as

    
    
    ...<span style=" font-family:'Ubuntu';">XYZ XYZ<br />XYZ</span>...
    #XYZ XYZ
    #XYZ
    

but it gives output without br tag.

    
    
    ...<span style=" font-family:'Ubuntu';">XYZ XYZXYZ</span>...
    #XYZ XYZXYZ
    

how can i correct this?


Answer: The problem is that you are redefining the `.string` of the element, but
instead I would find the "text" nodes and made the replacement there:

    
    
    for text in elm.find_all(text=True):
        text.replace_with(text.replace("A", "X").replace("B", "Y").replace("C", "Z"))
    

Works for me, produces:

    
    
    </p>
      <p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">
       <span style=" font-family:'Ubuntu';">
        XYZ XYZ
        <br/>
        XYZ
       </span>
    </p>
    

> how can i include this part in a loop?

Here is a sample:

    
    
    replacements = {
        "A": "X",
        "B": "Y",
        "C": "Z"
    }
    for text in elm.find_all(text=True):
        text_to_replace = text
        for k, v in replacements.items():
            text_to_replace = text_to_replace.replace(k, v)
    
        text.replace_with(text_to_replace)
    

