Add a line to a file if it not exist using python - python

I have an xml file as follows:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build" ToolsVersion="4.0">
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
I want to add a line <Import Project="$(ProjectName).targets" /> between
</ImportGroup> and </Project> as follows
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build" ToolsVersion="4.0">
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<Import Project="$(ProjectName).targets" />
</Project>
If the line <Import Project="$(ProjectName).targets" /> already exists in file there is no need to add.
How can I do that?

Your question is based on lines in text files, but the input file is clearly XML, so assuming you actually want to add an Import if it doesn't exist, try this:
import xml.dom.minidom
importstring = "$(Projectname).targets"
filename = "test.xml"
tree = xml.dom.minidom.parse(filename)
Project = tree.getElementsByTagName("Project")[0]
for Import in Project.getElementsByTagName("Import"):
if Import.getAttribute("Project") == importstring:
break
else: # note this is else belongs to the for, not the if
newImport = xml.dom.minidom.Element("Import")
newImport.setAttribute("Project", importstring)
Project.appendChild(newImport)
tree.writexml(open(filename, 'w'))

Take the XML parser of your choice, parse the file, manipulate the file using the related API, write it back.

Related

Adding an attribute to every XML element in an XLIFF file

I want to add xml:space="preserve" to every element in Xliff files like this one:
<?xml version="1.0" encoding="utf-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file datatype="plaintext" source-language="en-US" target-language="de-DE" date="2023-01-19T14:30:55Z" xml:space="preserve">
<body>
<trans-unit size-unit="char" approved="no" maxwidth="70" id="TITLE">
<source>Add test scripts to execution queue</source>
<target state="translated">Testskripte zur Ausführungs-Queue hinzufügen</target>
</trans-unit>
<trans-unit size-unit="char" approved="no">
<source>Dynamic ID</source>
<target state="translated">Dynamic-ID</target>
</trans-unit>
<trans-unit size-unit="char" approved="no" maxwidth="132">
<source>Identification</source>
<target state="translated">Identifikation</target>
</trans-unit>
</body>
</file>
</xliff>
The Python script I have looks like this, but also adds ns0: to the beginning of each element in the XML file.
import xml.etree.ElementTree as ET
tree = ET.parse("input.xlf")
root = tree.getroot()
for trans_unit in root.iter("{urn:oasis:names:tc:xliff:document:1.2}trans-unit"):
trans_unit.attrib["{http://www.w3.org/XML/1998/namespace}space"] = "preserve"
tree.write("output.xlf")
Why does that happen and can someone help to improve the script?
OK, adding ET.register_namespace("", "urn:oasis:names:tc:xliff:document:1.2")
and then also encoding='utf-8', xml_declaration=True) to the tree.write statement did the trick.
Thanks, #mzjn!

How to pass some variable values to RML file in Python?

Given an RML template, used to generate PDF file in python, how can one use variables declared in a Python script in the RML template file?
def create_pdf:
name = "My Name"
with open('/file.rml') as rml:
data = rml.read()
pdf = rml2pdf.parseString(data)
with open(f"/newpdf.pdf", 'wb') as output:
output.write(pdf.read())
return HttpResponse(status=200)
Here is the template file.rml:
<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<!DOCTYPE document SYSTEM "rml_1_0.dtd">
<document filename="file.rml">
.....
<story>
<para style="h1-center">[[name]]</para> <!-- Name value should appear here -->
</story>
</document>
So how do I get the name variable value in the template?
You may preprocess your file with genshi:
<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<!DOCTYPE document SYSTEM "rml_1_0.dtd">
<document xmlns:py="http://genshi.edgewall.org/" filename="file.rml">
.....
<story>
<para style="h1-center" py:content="name" /> <!-- Name value should appear here -->
</story>
</document>
Genshi template > RML file > PDF
https://genshi.readthedocs.io/en/latest/templates/

How to replace xml lines using 'if statements' in python?

Hi I'm new to xml files in general, but I am trying to replace specific lines in a xml file using 'if statements' in python 3.6. I've been looking at suggestions to use ElementTree, but none of the posts online quite fit the problem I have, so here I am.
My file is as followed:
<?xml version="1.0" encoding="UTF-8"?>
-<StructureDefinition xmlns="http://hl7.org/fhir">
<url value="http://example.org/fhir/StructureDefinition/MyObservation"/>
<name value="MyObservation"/>
<status value="draft"/>
<fhirVersion value="3.0.1"/>
<kind value="resource"/>
<abstract value="false"/>
<type value="Observation"/>
<baseDefinition value="http://hl7.org/fhir/StructureDefinition/Observation"/>
<derivation value="constraint"/>
</StructureDefinition>
I want to replace
url value="http://example.org/fhir/StructureDefinition/MyObservation"/
to something like
url value="http://example.org/fhir/StructureDefinition/NewObservation"/
by using conditional statements - because these are repeated multiple times in other files.
I have tried for-looping through the xml find to find the exact string match (which I've succeeded), but I wasn't able to delete, or replace the line (probably having to do with the fact that this isn't a .txt file).
Any help is greatly appreciated!
Your sample file contains a "-"-token in ln 3 that may be overlooked when copy/pasting in order to find a solution.
Input File
<?xml version="1.0" encoding="UTF-8"?>
<StructureDefinition xmlns="http://hl7.org/fhir">
<url value="http://example.org/fhir/StructureDefinition/MyObservation"/>
<name value="MyObservation"/>
<status value="draft"/>
<fhirVersion value="3.0.1"/>
<kind value="resource"/>
<abstract value="false"/>
<type value="Observation"/>
<baseDefinition value="http://hl7.org/fhir/StructureDefinition/Observation"/>
<derivation value="constraint"/>
</StructureDefinition>
Script
from xml.dom.minidom import parse # use minidom for this task
dom = parse('june.xml') #read in your file
search = "http://example.org/fhir/StructureDefinition/MyObservation" #set search value
replace = "http://example.org/fhir/StructureDefinition/NewObservation" #set replace value
res = dom.getElementsByTagName('url') #iterate over url tags
for element in res:
if element.getAttribute('value') == search: #in case of match
element.setAttribute('value', replace) #replace
with open('june_updated.xml', 'w') as f:
f.write(dom.toxml()) #update the dom, save as new xml file
Output file
<?xml version="1.0" ?><StructureDefinition xmlns="http://hl7.org/fhir">
<url value="http://example.org/fhir/StructureDefinition/NewObservation"/>
<name value="MyObservation"/>
<status value="draft"/>
<fhirVersion value="3.0.1"/>
<kind value="resource"/>
<abstract value="false"/>
<type value="Observation"/>
<baseDefinition value="http://hl7.org/fhir/StructureDefinition/Observation"/>
<derivation value="constraint"/>
</StructureDefinition>

Adding XML file to the last element of existing XML using Python

I have a XML file like this, let's name is XML_old:
<?xml version="1.0" encoding="UTF-8"?>
<!--
// Description : ahbbus12alda.xml
// modifications; this notice must be included on any copy.
-->
<ipxact:component xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ipxact="http://www.accellera.org/XMLSchema/IPXACT/1685-2014"
xsi:schemaLocation="http://www.accellera.org/XMLSchema/IPXACT/1685-2014
http://www.accellera.org/XMLSchema/IPXACT/1685-2014/index.xsd">
<ipxact:vendor>spiritconsortium.org</ipxact:vendor>
<ipxact:library>Leon2RTL</ipxact:library>
<ipxact:name>ahbbus12</ipxact:name>
<ipxact:version>1.3</ipxact:version>
<ipxact:busInterfaces>
<ipxact:busInterface>
<ipxact:name>AHBClk</ipxact:name>
</ipxact:busInterface>
</ipxact:busInterfaces>
</ipxact:component>
Also, I have another XML file, XML_1, like:
<?xml version="1.0" encoding="UTF-8"?>
<ipxact:component1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ipxact="http://www.accellera.org/XMLSchema/IPXACT/1685-2014"
xsi:schemaLocation="http://www.accellera.org/XMLSchema/IPXACT/1685-2014
http://www.accellera.org/XMLSchema/IPXACT/1685-2014/index.xsd">
<ipxact:vendor1>spiritconsortium.org</ipxact:vendor1>
<ipxact:library1>Leon2RTL</ipxact:library1>
<ipxact:name1>ahbbus34</ipxact:name1>
<ipxact:version1>1.3</ipxact:version1>
<ipxact:busInterfaces1>
<ipxact:busInterface1>
<ipxact:name1>AHBClk</ipxact:name1>
<ipxact:busInterface1>
<ipxact:busInterfaces1>
</ipxact:component1>
I want to add XML_1 to the XML_old as a last child of component element in XML_old file and create a new XML file like
<?xml version="1.0" encoding="UTF-8"?>
<!--
// Description : ahbbus12alda.xml
// modifications; this notice must be included on any copy.
-->
<ipxact:component xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ipxact="http://www.accellera.org/XMLSchema/IPXACT/1685-2014"
xsi:schemaLocation="http://www.accellera.org/XMLSchema/IPXACT/1685-2014
http://www.accellera.org/XMLSchema/IPXACT/1685-2014/index.xsd">
<ipxact:vendor>spiritconsortium.org</ipxact:vendor>
<ipxact:library>Leon2RTL</ipxact:library>
<ipxact:name>ahbbus12</ipxact:name>
<ipxact:version>1.3</ipxact:version>
<ipxact:busInterfaces>
<ipxact:busInterface>
<ipxact:name>AHBClk</ipxact:name>
</ipxact:busInterface>
</ipxact:busInterfaces>
<ipxact:component1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ipxact="http://www.accellera.org/XMLSchema/IPXACT/1685-2014"
xsi:schemaLocation="http://www.accellera.org/XMLSchema/IPXACT/1685-2014
http://www.accellera.org/XMLSchema/IPXACT/1685-2014/index.xsd">
<ipxact:vendor1>spiritconsortium.org</ipxact:vendor1>
<ipxact:library1>Leon2RTL</ipxact:library1>
<ipxact:name1>ahbbus34</ipxact:name1>
<ipxact:version1>1.3</ipxact:version1>
<ipxact:busInterfaces1>
<ipxact:busInterface1>
<ipxact:name1>AHBClk</ipxact:name1>
<ipxact:busInterface1>
<ipxact:busInterfaces1>
</ipxact:component1>
</ipxact:component>
I wonder how can I do this? I appreciate if you can help me.

Combine XML files similar to ConfigParser's multiple file support

I'm writing an application configuration module that uses XML in its files. Consider the following example:
<?xml version="1.0" encoding="UTF-8"?>
<Settings>
<PathA>/Some/path/to/directory</PathA>
<PathB>/Another/path</PathB>
</Settings>
Now, I'd like to override certain elements in a different file that gets loaded afterwards. Example of the override file:
<?xml version="1.0" encoding="UTF-8"?>
<Settings>
<PathB>/Change/this/path</PathB>
</Settings>
When querying the document (with overrides) with XPath, I'd like to get this as the element tree:
<?xml version="1.0" encoding="UTF-8"?>
<Settings>
<PathA>/Some/path/to/directory</PathA>
<PathB>/Change/this/path</PathB>
</Settings>
This is similar to what Python's ConfigParser does with its read() method, but done with XML. How can I implement this?
You could convert the XML into an instance of Python class:
import lxml.etree as ET
import io
class Settings(object):
def __init__(self,text):
root=ET.parse(io.BytesIO(text)).getroot()
self.settings=dict((elt.tag,elt.text) for elt in root.xpath('/Settings/*'))
def update(self,other):
self.settings.update(other.settings)
text='''\
<?xml version="1.0" encoding="UTF-8"?>
<Settings>
<PathA>/Some/path/to/directory</PathA>
<PathB>/Another/path</PathB>
</Settings>'''
text2='''\
<?xml version="1.0" encoding="UTF-8"?>
<Settings>
<PathB>/Change/this/path</PathB>
</Settings>'''
s=Settings(text)
s2=Settings(text2)
s.update(s2)
print(s.settings)
yields
{'PathB': '/Change/this/path', 'PathA': '/Some/path/to/directory'}
Must you use XML? The same could be achieved with JSON much simpler:
Suppose this is the text from the first config file:
text='''
{
"PathB": "/Another/path",
"PathA": "/Some/path/to/directory"
}
'''
and this is the text from the second:
text2='''{
"PathB": "/Change/this/path"
}'''
Then to merge the to, you simply load each into a dict, and call update:
import json
config=json.loads(text)
config2=json.loads(text2)
config.update(config2)
print(config)
yields the Python dict:
{u'PathB': u'/Change/this/path', u'PathA': u'/Some/path/to/directory'}

Categories