How to replace part of string and create a new file with replaced data

Viewed 24

I am trying to create a script to enrich the metadata of my ebook collection. The search for metadata is already complete, what I'm struggling with is how to get the data into the metadata file (example here: pastebin) This is an opf file which is used by calibre to store metadata.

For now, I'm interested in the line 27 (<meta name="calibre:user_metadata:#tags" ...) In the example file, I have added testtags, in order to find the position of the data and am now testing to replace the testtag with the tags that I got from another part of the script. This is my script so far:

import variables
from bs4 import BeautifulSoup
import json
tags=['test3','test4']
files=variables.test
for file in files:
    f=open(file,'r')
    data=f.read()
    #f.close()
    
    soup=BeautifulSoup(data,'lxml')
    for meta in soup.find_all('meta'):
        if meta.get('name')=='calibre:user_metadata:#tags':
            metastr=str(meta)
            splitter=meta.get('content')
            splitterjson=json.loads(splitter)
            splitterjson['#value#']=tags
            splitterstr=str(splitterjson)
            splitterstr=splitterstr.replace("\'","\"")
            #replace splitter with splitterstr
            splitter=splitter.replace(splitter,splitterstr)
            #in data replace metastr with splitter
            newdata=data.replace(metastr,splitter)
            print(newdata)

As it is right now, for some reason, the data will still have the old data instead of the new one. Afterwards, the script should open the file, replace the data with the new data and continue on.

How can I get the newdata to have the values I want? Is there anything I did wrong? Any answer is appreciated.

1 Answers

To change the content= of the one <meta> you can use next example:

import json
from bs4 import BeautifulSoup


with open("input.xml", "r") as f_in:
    soup = BeautifulSoup(f_in.read(), "xml")

meta = soup.select_one('meta[name="calibre:user_metadata:#tags"]')
data = json.loads(meta["content"])

data["#value#"] = ["test3", "test4"]

meta["content"] = json.dumps(data)

with open("output.xml", "w") as f_out:
    print(soup.prettify(), file=f_out)

This will create output.xml with changed calibre:user_metadata:#tags meta tag (changed to tag3 and tag4):

<?xml version="1.0" encoding="utf-8"?>
<package unique-identifier="uuid_id" version="2.0" xmlns="http://www.idpf.org/2007/opf">
 <opf:metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
  <dc:identifier id="calibre_id" opf:scheme="calibre">
   12012
  </dc:identifier>
  <dc:identifier id="uuid_id" opf:scheme="uuid">
   87b7295a-548f-4a11-a625-d68c98a6365a
  </dc:identifier>
  <dc:title/>
  <dc:creator opf:file-as="" opf:role="aut">
   A
  </dc:creator>
  <dc:contributor opf:file-as="calibre" opf:role="bkp">
   calibre (5.42.0) [https://calibre-ebook.com]
  </dc:contributor>
  <dc:date>
   2019-03-19T20:55:40+00:00
  </dc:date>
  <dc:description/>
  <dc:publisher>
   <dc:publisher>
    <dc:identifier opf:scheme="GOOGLE"/>
    <dc:identifier opf:scheme="ISBN"/>
    <dc:language>
     eng
    </dc:language>
    <dc:subject>
     Light Novel
    </dc:subject>
    <opf:meta content='{"": ""}' name="calibre:author_link_map"/>
    <opf:meta content="" name="calibre:series"/>
    <opf:meta content="" name="calibre:series_index"/>
    <opf:meta content="2021-04-16T19:06:02+00:00" name="calibre:timestamp"/>
    <opf:meta content="" name="calibre:title_sort"/>
    <opf:meta content='{"table": "custom_column_23", "column": "value", "datatype": "text", "is_multiple": "|", "kind": "field", "name": "Alias", "search_terms": ["#aka"], "label": "aka", "colnum": 23, "display": {"is_names": false, "description": ""}, "is_custom": true, "is_category": true, "link_column": "value", "category_sort": "value", "is_csp": false, "is_editable": true, "rec_index": 22, "#value#": ["testalias"], "#extra#": null, "is_multiple2": {"cache_to_list": "|", "ui_to_list": ",", "list_to_ui": ", "}}' name="calibre:user_metadata:#aka"/>
    <opf:meta content='{"table": "custom_column_9", "column": "value", "datatype": "text", "is_multiple": "|", "kind": "field", "name": "Genres", "search_terms": ["#genres"], "label": "genres", "colnum": 9, "display": {"is_names": false, "description": ""}, "is_custom": true, "is_category": true, "link_column": "value", "category_sort": "value", "is_csp": false, "is_editable": true, "rec_index": 23, "#value#": ["testgenre"], "#extra#": null, "is_multiple2": {"cache_to_list": "|", "ui_to_list": ",", "list_to_ui": ", "}}' name="calibre:user_metadata:#genres"/>
    <opf:meta content='{"table": "custom_column_4", "column": "value", "datatype": "text", "is_multiple": null, "kind": "field", "name": "Main Title", "search_terms": ["#main"], "label": "main", "colnum": 4, "display": {"description": "Haupttitle", "use_decorations": 0}, "is_custom": true, "is_category": true, "link_column": "value", "category_sort": "value", "is_csp": false, "is_editable": true, "rec_index": 24, "#value#": null, "#extra#": null, "is_multiple2": {}}' name="calibre:user_metadata:#main"/>
    <opf:meta content='{"table": "custom_column_12", "column": "value", "datatype": "text", "is_multiple": "|", "kind": "field", "name": "People", "search_terms": ["#ppl"], "label": "ppl", "colnum": 12, "display": {"is_names": false, "description": ""}, "is_custom": true, "is_category": true, "link_column": "value", "category_sort": "value", "is_csp": false, "is_editable": true, "rec_index": 25, "#value#": [], "#extra#": null, "is_multiple2": {"cache_to_list": "|", "ui_to_list": ",", "list_to_ui": ", "}}' name="calibre:user_metadata:#ppl"/>
    <opf:meta content='{"table": "custom_column_6", "column": "value", "datatype": "text", "is_multiple": null, "kind": "field", "name": "Sub Title", "search_terms": ["#sub"], "label": "sub", "colnum": 6, "display": {"description": "Nebentitel", "use_decorations": 0}, "is_custom": true, "is_category": true, "link_column": "value", "category_sort": "value", "is_csp": false, "is_editable": true, "rec_index": 26, "#value#": null, "#extra#": null, "is_multiple2": {}}' name="calibre:user_metadata:#sub"/>
    <opf:meta content='{"table": "custom_column_21", "column": "value", "datatype": "text", "is_multiple": "|", "kind": "field", "name": "My Tags", "search_terms": ["#tags"], "label": "tags", "colnum": 21, "display": {"is_names": false, "description": ""}, "is_custom": true, "is_category": true, "link_column": "value", "category_sort": "value", "is_csp": false, "is_editable": true, "rec_index": 27, "#value#": ["test3", "test4"], "#extra#": null, "is_multiple2": {"cache_to_list": "|", "ui_to_list": ",", "list_to_ui": ", "}}' name="calibre:user_metadata:#tags"/>
    <opf:meta content='{"table": "custom_column_17", "column": "value", "datatype": "composite", "is_multiple": ",", "kind": "field", "name": "Vol.", "search_terms": ["#vol"], "label": "vol", "colnum": 17, "display": {"composite_template": "{series_index}", "composite_sort": "number", "make_category": false, "contains_html": false, "description": ""}, "is_custom": true, "is_category": false, "link_column": "value", "category_sort": "value", "is_csp": false, "is_editable": true, "rec_index": 28, "#value#": "3", "#extra#": null, "is_multiple2": {"cache_to_list": ",", "ui_to_list": ",", "list_to_ui": ", "}}' name="calibre:user_metadata:#vol"/>
   </dc:publisher>
   <opf:guide>
    <opf:reference href="cover.jpg" title="Cover" type="cover"/>
   </opf:guide>
  </dc:publisher>
 </opf:metadata>
</package>
Related