How to add a line break to each XML node? - c++

How can I add a line break to each XML child bode so the output looks formatted?
The template file contains <Faults> and </Faults> tags. Now I want to insert a line break inside this node.
C++ CODE:
_di_IXMLNode nodeFault = NULL;
IXMLNode *m_pRootNode = FormMain->GetBBReportTXMLDocPtr()->DocumentElement;
...
for(; it_Events != lstEvent.end(); it_Events++){
nodeFault = m_pRootNode->ChildNodes[EVENT_REPORT].Get(EXmlTagOrder::extoFaults)->AddChild("Fault");
nodeFault->Attributes[WideString("Entry")] = ((*it_Events).m_sEntry).c_str();
nodeFault->AddChild("Time")->Text = ((*it_Events).m_sTimeStamp).c_str();
nodeFault->AddChild("Code")->Text = ((*it_Events).m_sCode).c_str();
}
But I am not getting output with line breaks or formatting.
When I open the XML file in Notepad, all nodes are on a single line:
<Faults><Fault Entry="0"><Time>0</Time><Code>20</Code></Fault><Fault Entry="1"><Time>2</Time><Code>10</Code></Faults>
The XML file looks formatted when I open it in Internet Explorer instead:
<Faults>
<Fault Entry="0">
<Time>0</Time>
<Code>20</Code>
</Fault>
<Fault Entry="1">
<Time>2</Time>
<Code>10</Code>
</Fault>
</Faults>
How can I add a line break to each node so my final output file looks formatted when I open it in Notepad++?

You have to set some formatting options before saving to file.
In your specific case:
FormMain->GetBBReportTXMLDocPtr()->Options =
FormMain->GetBBReportTXMLDocPtr()->Options << doNodeAutoIndent

Look at the FormatXMLData() function:
Formats a string of XML so that it is more readable.
Use FormatXMLData to convert a string of XML into a format that represents its structure. FormatXMLData changes the input string (XMLData) so that each element node appears on its own line, indented appropriately to reflect its nesting in the node hierarchy.

Related

How to create a xml node using rapidxml

Hi I want to create the following xml file in C++ using rapidxml on Linux.
How to add an element which is of type name.
<wrapit>
<mainNode>
<name>something1</name>
</mainNode>
</wrapit>
what my code generates looks like following which I don't want.
<wrapit>
<mainNode>
<name something1=""/>
</mainNode>
</wrapit>
I could not find much information for this. Few on wordpress but the xml formats are different.
Code snippet
xml_node<>* root = doc.allocate_node(node_element, "mainNode");
doc.append_node(root);
xml_node<>* child = doc.allocate_node(node_element,"name");
child->append_attribute(doc.allocate_attribute("something1"));
root->append_node(child);
ugg....
xml_node<>* child = doc.allocate_node(node_element,"name","something1");
does it.

Add XML contained in string as XML nodes to existing pugixml tree

I have a configuration file saver/loader. In addition to the expected data, there is a <CustomData> node. When saving the node, we'd simply have a std::string _customData and add it to the node, like this:
pugi::xml_document doc;
pugi::xml_node config = doc.append_child("OurConfig");
// save custom data
pugi::xml_node customData = config.append_child("CustomData");
customData.append_child(pugi::node_pcdata).set_value(_customData);
Our _customData was base64 encoded XML. It is provided from another part of the application. It must be a string, since the other part of the application uses different programming language (C#). As you can imagine, that became annoying, because it wasn't human readable. First step to fix this was simply to get rid of base64 in the app that provides _customData. So now we have readable version, which looks like this:
<?xml version="1.0"?>
<OurConfig>
<CustomData><CfgRoot>
<SomeValue name="External setting for foo" value="Foo"/>
<SomeValue name="External setting for bar" value="Bar"/>
</CfgRoot></CustomData>
</OurConfig>
But it could probably improve if the custom data was directly appended to XML tree instead of as string value. How can I append XML string as XML and not as string to pugixml tree?
Ie. the output I'd like:
<?xml version="1.0"?>
<OurConfig>
<CustomData>
<CfgRoot>
<SomeValue name="External setting for foo" value="Foo"/>
<SomeValue name="External setting for bar" value="Bar"/>
</CfgRoot>
</CustomData>
</OurConfig>
In the docs, there are three methods listed. I used the first one, making a convenience function like this:
bool AppendXMLString(pugi::xml_node target, const std::string& srcString)
{
// parse XML string as document
pugi::xml_document doc;
if (!doc.load_buffer(srcString.c_str(), srcString.length()))
return false;
for (pugi::xml_node child = doc.first_child(); child; child = child.next_sibling())
target.append_copy(child);
return true;
}

Parsing XML file with elementtree: 'NoneType' object has no attribute 'text'

I'm trying to parse information from an XML file using ElementTree in Python 2.7.
The XML file has the following structure:
<EXPERIMENT_PACKAGE_SET>
<EXPERIMENT_PACKAGE>
<SAMPLE>
<IDENTIFIERS>
<PRIMARY_ID>ERS1486582</PRIMARY_ID>
<EXTERNAL_ID>SAMEA36350668</EXTERNAL_ID>
</IDENTIFIERS>
<SAMPLE_ATTRIBUTES>
<SAMPLE_ATTRIBUTE>
<TAG>collection date</TAG>
<VALUE>2011</VALUE>
</SAMPLE_ATTRIBUTE>
<SAMPLE_ATTRIBUTE>
<TAG>geographic location</TAG>
<VALUE>USA</VALUE>
</SAMPLE_ATTRIBUTE>
...
</SAMPLE_ATTRIBUTES>
</SAMPLE>
...
</EXPERIMENT_PACKAGE>
</EXPERIMENT_PACKAGE_SET>
It contains many "Sample" modules that I want to loop over, parse some information from the "Identifiers" module and then loop again within their list of "Sample attributes" to store them in a file, including for each of them both their "Tag" and "Value". These data are not standardized (ie the attributes' tags don't always match) so I want to output all of them for each Sample. I wrote this piece of code that worked with other XML files with the same structure:
# import the XML file
e = xml.etree.ElementTree.parse('file.xml').getroot()
# create output file
file = open('output.txt','w')
# loop over all "Sample" modules
for i in range(0,len(e.findall('EXPERIMENT_PACKAGE/SAMPLE'))):
node = e.findall('EXPERIMENT_PACKAGE/SAMPLE')[i]
accession = node.find('IDENTIFIERS/PRIMARY_ID').text
sample = node.find('IDENTIFIERS/EXTERNAL_ID').text
# loop over the list of attributes and print 'accession', 'sample', and for each attribute, 'tag' and 'value'
for attribute in node.findall('SAMPLE_ATTRIBUTES/SAMPLE_ATTRIBUTE'):
file.write(accession + '\t' + sample + '\t' + str(attribute.find('TAG').text) + '\t' +
str(attribute.find('VALUE').text) + '\n')
file.close()
This code worked in the past, and it should give an output such as:
> ERS1486582 SAMEA36350668 collection date 2011
> ERS1486582 SAMEA36350668 geographic location USA
> ...
But with this particular XML file is giving me an error:
AttributeError: 'NoneType' object has no attribute 'text'
I guess some element has None value? How could I try to check if the elements are not NoneType before writing out their values? I've tried adding an 'if' condition like:
if attribute.find('VALUE').text is not None:
within the second 'for' loop (before writing in the output file) but it's not working either. Thanks very much for your help and sorry if I didn't express myself clearly.

Tinyxml2 append function

I have been looking for a way to append my xml file using tinyxml2 but couldn't find anything. I would appreciate any help.
Here is my code:
function savedata() {
XMLNode * pRoot = xmlDoc.NewElement("Cars");
xmlDoc.InsertFirstChild(pRoot);
XMLElement * pElement = xmlDoc.NewElement("Brand");
pElement->SetText("Audi");
pRoot->InsertEndChild(pElement);
pElement = xmlDoc.NewElement("type");
pElement->SetText("4x4");
pRoot->InsertEndChild(pElement);
pElement = xmlDoc.NewElement("Date");
pElement->SetAttribute("day", 26);
pElement->SetAttribute("month", "April");
pElement->SetAttribute("Year", 2015);
pElement->SetAttribute("dateFormat", "26/04/2015");
pRoot->InsertEndChild(pElement);
XMLError eResult = xmlDoc.SaveFile("SavedData1.xml");
XMLCheckResult(eResult);
}
Everytime I run the function, the xml is overwritten and I want to append to the existing file.
My xml file:
<Cars>
<Brand>Audi</Brand>
<Whatever>anothercrap</Whatever>
<Date day="26" month="April" Year="2015" dateFormat="26/04/2015"/>
</Cars>
My root is and I want to append to the existing file. For example,
<Cars>
<Brand>Audi</Brand>
<type>4x4</type>
<Date day="26" month="April" Year="2015" dateFormat="26/04/2015"/>
<Brand>BMWM</Brand>
<type>truck</type>
<Date day="26" month="April" Year="2015" dateFormat="26/04/2015"/>
</Cars>
XML is structured data so a textual append would be tricky and possibly error-prone, as you would have to make sure you don't add the root node twice, and that you maintain indentation etc.
What might be easier is to load the XML, parse it with TinyXML, and write it back.
You can append if you use the FILE overload for xmldoc.Save.
FILE* file = fopen("myfile.xml","a");
xmlDoc.Save(file);
fclose(file);
You just have to be careful when doing this since it will mess up the doc if you're printing multiple root nodes. If you're doing this for logging purposes I would just leave out the root node entirely and just have whatever is reading the log back know to append them or just not even care about proper xml format.

How to replace text in content control after, XML binding using docx4j

I am using docx4j 2.8.1 with Content Controls in my .docx file. I can replace the CustomXML part by injecting my own XML and then calling BindingHandler.applyBindings after supplying the input XML. I can add a token in my XML such as ¶ then I would like to replace that token in the MainDocumentPart, but using that approach, when I iterate through the content in the MainDocumentPart with this (link) method none of my text from my XML is even in the collection extracted from the MainDocumentPart. I am thinking that even after binding the XML, it remains separate from the MainDocumentPart (??)
I haven't tried this with anything more than a little test doc yet. My token is the Pilcrow: ¶. Since it's a single character, it won't be split in separate runs. My code is:
private void injectXml (WordprocessingMLPackage wordMLPackage) throws JAXBException {
MainDocumentPart part = wordMLPackage.getMainDocumentPart();
String xml = XmlUtils.marshaltoString(part.getJaxbElement(), true);
xml = xml.replaceAll("¶", "</w:t><w:br/><w:t>");
Object obj = XmlUtils.unmarshalString(xml);
part.setJaxbElement((Document) obj);
}
The pilcrow character comes from the XML and is injected by applying the XML bindings to the content controls. The problem is that the content from the XML does not seem to be in the MainDocumentPart so the replace doesn't work.
(Using docx4j 2.8.1)