Dicttoxml Module tags - python-3.x

I have been trying to make use of this module for some time now. I have many lists of dictionaries, that I want to convert into xml format. However, I want each list to essentially have its own 'table'. However When I try doing something along the lines of:
xml = dicttoxml.dictoxml(myList, root = False,
custom_root = "MyName",
attr_type = False)
I get every dict displayed as an <item> type. Shouldn't this produce what the module's owner refers to as an "xml snippet" that also is identified by the custom_root name?
Essentially I want each list to have its own identifier but not be created as 'root'. Basically where the following would have each item number associated to a certain list. Either encapsulating the whole list or each dict in the list would be suitable, I believe.
<root>
<item1>
#dict info
</item1>
<item2>
#dict info
</item2>
</root>

I fixed my problem by using just the custom_root variable in my call and leaving root = True. Then, I stripped the leading
b'<?xml version="1.0" encoding="UTF-8" ?>'
by calling
xml.partition(b'<?xml version="1.0" encoding="UTF-8" ?>')[2]
From then on, I created a file with <root> </root> tags and had the xml i created appended in between these tags.

Related

Deleting entire columns and whitespace in .xml file

Working with an xml file that contains excess whitespace and empty columns that I need to delete. So far, I've been able to delete specific node objects and/or elements of a node. I've been told previously that with xml files, you can't necessarily pinpoint or target whitespace in the file, but rather, you must replace it. How would I go about that?
Listed below is my code to remove either an entire node or a specific element within a node object. For example sake, let's assume we are using the following document:
https://docs.python.org/3/library/xml.etree.elementtree.html#modifying-an-xml-file
I'm using elementtree, not panda or dom.
# To remove an entire node and all of its elements
# for country in root.findall('country'):
# using root.findall() to avoid removal during traversal
# description = country.find('description').text
# if description == " Yurr ":
# root.remove(country)
# To remove a specific element or node within
# a node
for country in root.findall('country'):
description_node = country.find('description')
# This will remove the specific node
# 'description' in the .xml file.
if description_node.text == 'Liechtenstein has a lot of flowers.':
country.remove(description_node)
tree.write('SampleData.xml')
In XSLT 3.0,
<xsl:transform version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="no"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="year"/>
</xsl:transform>
will strip all indentation whitespace and remove elements named year. Is that what you're after?

Copy elements using xsl:copy-of without attributes

I have a xml like shown below
<?xml version="1.0" encoding="UTF-8"?>
<schools>
<city>Marshall</city>
<state>Maryland</state>
<highschool>
<schoolname>Marshalls</schoolname>
<department id="1">
<deptCode seq="1">D1</deptCode>
<deptName seq="2">Chemistry</deptName>
<deptHead seq="3">Henry Carl</deptHead>
<deptRank seq="4">L</deptRank>
</department>
<department id="2">
..
..
..
</highschool>
</schools>
In XSL i am copying the contents from department based on deptCode using
<xsl:copy-of select="*">
This produces result with all the attributes in the element tags.
Is it possible to ignore the attributes while using xsl:copy-of?
The desired result is like shown below
<deptCode>D1</deptCode>
<deptName>Chemistry</deptName>
<deptHead>Henry Carl</deptHead>
<deptRank>L</deptRank>
xsl:valueOf is working as required but i am trying to know if it
can be done with in xsl:copy-of? As a note, in my requirement, there are nearly 5 or 6 attributes for each element. Can someone please help? Thanks in Advance..
regards
Udayakiran
xsl:valueOf is working as required but i am trying to know if it can
be done with in xsl:copy-of?
No. xsl:copy-of is a package deal, you cannot pick and choose. To avoid repetitive coding, use a template matching department/*.

SlowCheetah transform ignores multiple conditions

I have a WCF configuration file that I am trying to transform with SlowCheetah. For development use, we want to include the MEX endpoints, but when we release the product, these endpoints should be removed on all services except one. The server for which it should be left has the following endpoint:
<endpoint address="MEX"
binding="mexHttpBinding"
contract="IMetadataExchange" />
The ones that should be removed are as follows:
<endpoint address="net.tcp://computername:8001/WCFAttachmentService/MEX"
binding="netTcpBinding"
bindingConfiguration="UnsecureNetTcpBinding"
name="WCFAttachmentServiceMexEndpoint"
contract="IMetadataExchange" />
The transform I am using is:
<service>
<endpoint xdt:Locator="Condition(contains(#address, 'MEX') and not(contains(#binding, 'mexHttpBinding')))" xdt:Transform="RemoveAll" />
</service>
However, when I run this, ALL MEX endpoints are removed from the config file including the one that I wish to keep. How do I make this work properly?
The Locator Condition expression that selects the nodes seems to be correct. If you had only the two endpoints you posted in your example, this expression will select the second endpoint.
According to the documentation the Transform attribute RemoveAll should "remove the selected element or elements." Based on the information you posted it's not working as expected, since the first element was not selected and was removed anyway. Based on this StackOverflow answer it seems to me that the issue is with Condition. I'm not sure if that's a bug (it's poorly documented), but you could try some alternative solutions:
1) Using XPath instead of Condition. The effective XPath expression that is applied to your configuration file as a result of the Condition expression is:
/services/service/endpoint[contains(#address, 'MEX') and not(contains(#binding, 'mexHttpBinding'))]
You should also obtain the same result using the XPath attribute instead of Condition:
<endpoint xdt:Locator="XPath(/services/service/endpoint[contains(#address, 'MEX')
and not(contains(#binding, 'mexHttpBinding'))])" xdt:Transform="RemoveAll" />
2) Using Match and testing an attribute such as binding. This is a simpler test, and would be IMO the preferred way to perform the match. You could select the nodes you want to remove by the binding attribute
<endpoint binding="netTcpBinding" xdt:Locator="Match(binding)" xdt:Transform="RemoveAll" />
3) UsingXPath instead of Match in case you have many different bindings and only want to eliminate only those which are not mexHttpBinding:
<endpoint xdt:Locator="XPath(/services/service/endpoint[not(#binding='mexHttpBinding'))" xdt:Transform="RemoveAll" />
4) Finally, you could try using several separate statements with Condition() or Match() to individually select the <endpoint> elements you wish to remove, and use xdt:Transform="Remove" instead of RemoveAll.

How to add top level element using Linq to XML

Assuming I have a xdocument called xd, with the following xml already created.
<Alert>
<Source>
<DetectTime>12:03:2010 12:22:21</DetectTime>
</Source>
</Alert>
How would I be able to add another Alert element, such that the xml becomes:
<Alert>
<Source>
<DetectTime>12:03:2010 12:22:21</DetectTime>
</Source>
</Alert>
<Alert>
</Alert>
Adding an additional elements seems to be fairly easy, but when adding in a top level element it excepts.
Your desired XML structure is invalid; you need a root element in order to add another "Alert" node. The following code shows how to add it when a root node exists:
var xdoc = XDocument.Parse(#"<root>
<Alert>
<Source>
<DetectTime>12:03:2010 12:22:21</DetectTime>
</Source>
</Alert>
</root>");
xdoc.Root.Add(new XElement("Alert"));
Console.WriteLine(xdoc);
The above code produces <Alert /> since no child nodes are added to it (this will change once you add to it). If you want the closing tag as you have shown you can use xdoc.Root.Add(new XElement("Alert", String.Empty)); instead.
To verify that your desired output has an invalid structure you can try parsing it using XDocument.Parse similar to what I've shown above.

Parsing Tableau xml does not preserve original file

I try to work programmatically on Tableau desktop file (which are just xml file in spite of their .twb extension). I have many problem with lxml which doesn't preserve original content. To facilitate the explanation, imagine you have a test.xml file which contain the following text:
<column caption='Choix Découpage' name='[Aujourd&apos;Hui Parameter (copy 2)]'>
<member name='Nb d&apos;annulations' default-format='n#,##0.00" annulations";-#,##0.00" annulations"' />
<run>
:</run>
<calculation formula='iif([FAC_TYPE] = &apos;Avoir&apos; , [Calculation_1378101492427309057], null)' />
<alias key='"Billetterie Ferroviaire"' value='Train ticketing' />
</column>
Now let's parse it:
tree = etree.parse('test.xml')
root = tree.getroot()
print(etree.tostring(root,pretty_print=True,).decode("utf-8"))
When you run the code we can notice:
' becomes "
é becomes é Edit: resolved for this part
&apos; becomes '
How could i preserve the original ? (It would help me a lot when i try to check the diff with git in spite of showing all the useless change that are operated automatically)
Edit: I notice an other problem, when i run the folowing code:
[node.attrib['key'] for node in root.xpath("//alias")]
I got the result: ['"Billetterie Ferroviaire"'] and I am now unable to query with xpath if i am looking for the node whose attribute "key" is the original "Billetterie Ferroviaire" (root.xpath('//[#key="Billetterie Ferroviaire"]) doesn't work)

Resources