I am trying to add new nodes to an element tree. These new nodes have childs in them. Is there anyway using lxml to add all these in one go.
Ex:
Old format
<Test>
<Header>
</Header>
</Test>
New format that I am trying to achieve by adding nodes
<Test>
<Header>
<Source>
<ProcessID> 234 </ProcessID>
<InstanceID> 1 </InstanceID>
</Source>
<Target>
<ProcessID> 234 </ProcessID>
<InstanceID> 1 </InstanceID>
</Target>
</Header>
</Test>
I am looking for 2 things:
1) Is there anyway by which I can add entire Source node and Target node in one go? I mean adding source node in one go and Target node in one go. Instead of adding source node and then processID and then InstanceID etc
2) At the moment I am maintaining changes in a flat file and storing the changes and then applying them using lxml
The problem I am facing is,
When I add Source node to Header node using Subelement it is not added as proper tag and only closure tag of Source is added. When I try to get Source element using find function I am getting element as null. Hence I can't add childs to Source node. As you can see Source node doesn't have any attributes or text, but it has childs.
Can you help me in adding this structure to element tree? I tried all the ways as much as I can. I am sure there should be a simple solution to do this instead of adding it one by one.
I have so many files to be treated like this, so looking for a simple solution.
TIA
Related
I am trying to parse am XML string using xerces c++.
The structure is
<root>
<optionA>
<optionB/>
</optionA>
</root>
I read the xml string into MemBufInputSource and then parse it.
When I call getChildNodes() on root, it always returns 2. Should it not be 1? Here, only option A is the child of root. Also, for each child I check if its a node and of type element. For the first child, the check is always false.
Why does it show a count of 2 children?
getChildNodes() returns all child nodes, not just the ones that are elements.
The whitespace between the elements (new lines in this case) count as a text node (DOMNode::NodeType::TEXT_NODE). By my count there are actually 2 text nodes in your example, so 3 child nodes overall, though differences when transcribing into the question, or different configuration of Xerces may have resulted in 2 child nodes in your original code.
If you change your XML example to be all on one line with no whitespace
<root><optionA><optionB/></optionA></root>
you can see that Xerces will then report that there is only one child of root.
Here is the full list of node types that Xerces may encounter.
I'm trying to transform one XML document (REQ-IF) into another XML document (UML-Class-Diagram document) using XSLT.
My Problem now is the following:
REQ-IF provides datatypes as:
<Datatypes>
<DATATYPE-DEFINITION-STRING IDENTIFIER="xyz" LONG-NAME="ABC"
</Datatypes>
and Objects as:
<SPEC-OBJECTS>
<VALUES>
<ATTRIBUTE-VALUE-STRING THE-VALUE="some-value">
<DEFINITION>
<ATTRIBUTE-DEFINITION-STRING-REF>xyz</ATTRIBUTE-DEFINITION-STRING-REF>
</DEFINITION>
</ATTRIBUTE-VALUE-STRING>
</VALUES
<SPEC-OBJECTS>
This is resembled in my UML representation as:
<ownedAttribute xmi:id="some-ID" name="ABC" type="some-ID">
please note the ABC and xyz.
I therefore use <xsl:for-each> to loop through the Objects and another <xsl:for-each> to loop through the values.
Now I have to take the Datatype-ID from the value, find out which Datatype it is and write the Datatype-name into the output file.
How do I do that?
Thank you so much in advance
Try /Datatypes[DATATYPE-DEFINITION-STRING/#IDENTIFIER = current()/ATTRIBUTE-VALUE-STRING/DEFINITION/ATTRIBUTE-DEFINITION-STRING-REF]/DATATYPE-DEFINITION-STRING/#LONG-NAME.
I admit I didn't actually test this, but you'll probably get the idea. The point of current is to access the XSLT context (the VALUES element) as opposed to the current XPath context that is active in the filter.
I'm seeing a quite odd behaviour, when trying to limit the results given by applying ancestor::* to an element I always get an extra ancestor although is expressly excluded by the predicate.
Here the code:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<level_a>
<level_b>
<level_c>
<level_d>
<level_e/>
</level_d>
</level_c>
</level_b>
</level_a>
<level_b>
<level_c>
<level_d>
<level_d>
<level_e/>
</level_d>
</level_d>
</level_c>
</level_b>
</root>
XPath:
(//level_d[not(level_d)])[last()]/ancestor::*[level_c|level_b]
so basically I'm selecting the level_d elements that doesn't have another level_d element nested, getting the last one of them and trying to get all the ancestors up to element level_b.
But the result I'm seeing using Altova XMLSpy 2011 is:
level_a
level_b
I don't quite understand why I'm getting that result and how can I improve my xpath to limit effectively the ancestors up to level_b (i.e. level_c and level_b).
Any hint is greatly appreciated!
Regards
Vlax
Well ancestor::*[level_c|level_b] selects all elements on the ancestor axis that have a level_c or level_b child.
You might want (//level_d[not(level_d)])[last()]/ancestor::*[self::level_c|self::level_b].
Or with your textual description "to limit effectively the ancestors to level_b" you simply want (//level_d[not(level_d)])[last()]/ancestor::level_b.
I think you get right result because clause ancestor::*[level_c|level_b] I read as "all ancestors containing element level_b or level_c". So, level_b is ok because it contains level_c and level_a is ok too because it contains level_b.
So if I change your XPath into (//level_d[not(level_d)])[last()]/ancestor::*[level_c] it results into level_b only.
Probably it is not exactly what you asking for but I'm not sure if I understand well the purpose of your XPath :-)
I have an XML as below
<ROOT>
<Device>
<host>localhost</host>
<Port>52000</Port>
</Device>
<DeviceHost>
<Server>Server.exe</Server>
<Port>81</Port>
</DeviceHost>
<Settings>
<Flag1>100</Flag1>
<Flag2>2000</Flag2>
</Settings>
</ROOT>
How can I update the Flag1 and Flag2 to 200 and 4000 respectively without changing other values using VC++?
I have two function wrote using api MSXML.
doc.LoadXml(Data);//for loading the xml data
doc.Save(FilePath);//for saving the xml data
But my issue is before saving how can i update two node values
You would need to get the correct node by calling getElementsByTagName (which should return a NodeList containing one item) and then call put_nodeValue to write the value -- there are some MSDN samples here and here
EDIT: you should also be able to use doc.selectSingleNode("/ROOT/Flag1", &pNode) as per this MSDN article
How can I find the last node that contains a specific structure?
<defect-event>
<event-assigned-to>
<assigned-to-user>
<last-name>Doe</last-name>
<first-name>John</first-name>
<middle-name></middle-name>
</assigned-to-user>
</event-assigned-to>
</defect-event>
There can be many "defect-event" nodes at the same level, below or above the one with the "assigned-to-user" sub node.
There can also be multiple "defect-event" nodes with the "assigned-to-user" sub node.
I need to find the last one "defect-event" node which contains the "assigned-to-user" sub node.
Thanks!
Something on these lines is probably what you want:
defect-event[event-assigned-to[assigned-to-user]][position()=last()]
In effect, you're saying "find me all the defect-event which contains an event-assigned-to containing an assigned-to-user, and then just give me the one whose position() is last()".
Having said that, you might need to tweak this depending on the context you're in when you try to find the node, and what you're doing to the node (eg: behaviour might vary if you're in a for-each loop as opposed to an apply-templates situation).