boost property tree adds empty line with write_xml() - c++

I am using boost (version 1.70.0) property tree. If I have this XML (no empty lines):
<Root>
<SomeOtherElement>..</SomeOtherElement>
<Collection>
<Item Attr1=".." attr2="" />
<Item Attr1=".." attr2="" />
</Collection>
</Root>
and I extract a node, insert to another (empty) tree:
auto node = pt.get_child("Root.Collection");
ptree new_pt{};
new_pt.put_child("Collection", node);
std::ostringstream os;
write_xml(os, new_pt);
auto xml = os.str();
I will get the output with empty lines, something like this:
<Collection>
<Item Attr1=".." attr2="" />
<Item Attr1=".." attr2="" />
</Collection>
I have tried different things. I can fix it by iterating over Item elements and adding one by one. Then it works, no extra lines. However, if Item element itself has a child element(s), then again, it will add a bunch of empty lines.

I think it's duplicated with this one, or it's just a bug in the property tree.
https://stackoverflow.com/a/6614372/1292791
To read with the trim flag will fix the problem:
pt::read_xml(filename, tree, boost::property_tree::xml_parser::trim_whitespace);
To write with pretty format:
pt::write_xml(os, tree, boost::property_tree::xml_writer_make_settings<std::string>(' ', 1));

Related

In XSLT nested foreach loop always return first element

XLST receiving the date from apache-camel in below formate.
data format
<list>
<linked-hash-map>
<entry key="NAME">test1</entry>
</linked-hash-map>
<linked-hash-map>
<entry key="NAME">test2</entry>
</linked-hash-map>
</list>
My XSLT:
<xsl:stylesheet>
<xsl:template match="*">
<xsl:for-each select="//*[local-name()='linked-hash-map']">
<tag1>
<xsl:value-of select="string(//*[local-name()='entry'][#key='NAME'])"/>
</tag1t>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
OUTPUT always returns the first element.
<tag1>test1<tag1>
<tag1>test1<tag1>
What is wrong in above xslt and help generate xml with all elements.
Because path expressions starting with "//" select from the root of the document tree, you are selecting the same nodes every time in your xsl:value-of; and in XSLT 1.0, if you select multiple nodes, only the first one gets displayed.
Methinks you're using "//" because you've seen it in example code and don't actually understand what it means...
Within xsl:for-each, you normally want a relative path that selects from the node currently being processed by the for-each.
You've also probably picked up this *[local-name()='linked-hash-map'] habit from other people's code. With no namespaces involved, you can safely replace it with linked-hash-map.

How to check for blank elements in XML?

Is there a regex to check for empty elements for the XML below? So I want to check whether or not everything below the <ClientRequest> tags are populated or not?
<Response xmlns="http://Test/Types">
<ClientRequest>
<Name>TEST</Name>
<Id><222/Id>
<Parameters>
<SID>123456</SID>
</RequestParams>
<StartDate>2017-10-13T23:00:01.000+01:00</StartDate>
<EndDate>2017-10-14T22:59:59.000+01:00</EndDate>
<URL></URL>
</ClientRequest>
<Install/>
<Types/>
<LR/>
<Package/>
<Services/>
<Issues/>
<Complaints/>
</Response>
Use an XML parser or XPath, not regex, to check or parse XML.
This XPath,
//*[not(text()) and not(*)]
will select all elements that have no text or element children.
This XPath,
//*[not(node())]
will select all empty elements (also disallowing comment and PI children).
Note that your XML is not well-formed. Here it is with corrections:
<Response xmlns="http://Test/Types">
<ClientRequest>
<Name>TEST</Name>
<Id>222</Id>
<Parameters>
<SID>123456</SID>
</Parameters>
<StartDate>2017-10-13T23:00:01.000+01:00</StartDate>
<EndDate>2017-10-14T22:59:59.000+01:00</EndDate>
<URL></URL>
</ClientRequest>
<Install/>
<Types/>
<LR/>
<Package/>
<Services/>
<Issues/>
<Complaints/>
</Response>
Note also that you could wrap either of the above XPaths in boolean() or count() to return an indicator or count of the presence of such populated elements.

XSLT understand about the generate-id working way

Further to this link xslt return selection of following siblings
I Just to want to know, here, what is purpose of this generate-id and how it is making sense in this matching protocol.
<xsl:for-each select="/items/item[#lcn='005417714']">
<xsl:for-each select="following-sibling::*[generate-id(preceding-sibling::item[#lcn != ''][1]) = generate-id(current())]">
</xsl:for-each>
</xsl:for-each>
Any idea, pls share.
The specification of generate-id is that it will always return the same ID for the same node and different IDs for different nodes. Thus, comparing the generate-id values of two nodes is the way you check whether they are the same node as opposed to just two nodes that happen to have the same value.
And current() gives you the current "top-level" context node - outside a predicate current() is the same as ., but inside a predicate expression . refers to the node the predicate is testing whereas current() still refers to the "outer .".
Now in your example
following-sibling::*[generate-id(preceding-sibling::item[#lcn != ''][1])
= generate-id(current())]
the outer context node is an item element (the one that the outer for-each is currently looking at). So starting from that item the expression will select:
following-sibling::* --- all the following sibling elements
[ --- such that
generate-id( --- the identity of
preceding-sibling::item[#lcn != ''][1] --- that element's nearest preceding
item with a non-empty lcn attribute
)
= --- is the same as
generate-id(current()) --- the identity of the item we started
with
]
in other words, all the sibling elements between this <item lcn="005417714"> (exclusive) and the next <item lcn="anything-non-empty"> (inclusive).
Taking an example from the linked question:
<item id="00100687" label="A/161i r" lcn="005417714" notes="A/161-182"/>
<item id="00100688" label="A/161i v" lcn="" notes=""/>
<item id="00100819" label="A/182ii v" lcn="" notes=""/>
<item id="00100820" label="A/182iii r" lcn="" notes=""/>
<item id="00100821" label="A/182iii v" lcn="" notes=""/>
<item id="00100822" label="A/183i r" lcn="005417715" notes="A/183-218"/>
<item id="00100823" label="A/183i v" lcn="" notes=""/>
<item id="00100975" label="A/216iii r" lcn="" notes=""/>
if the current context node is the item with id="00100687" then that select would pull out items 00100688, 00100819, 00100820, 00100821 and 00100822. If you wanted to exclude 00100822 you'd have to add another predicate
following-sibling::*[#lcn = '']
[generate-id(preceding-sibling::item[#lcn != ''][1])
= generate-id(current())]

XSLT 2.0 - Two steps sorting

my XML tag contains many items that should be threated as three different groups, with similar (but different) sorting rules.
This is what I want to get:
<items>
<!-- Header - for-each sorting -->
<item name="something1_A"/>
<item name="something2_B"/>
<item name="something3_C"/>
<!-- Body - for-each-group sorting -->
<item name="something4_D"/>
<item name="something4_E"/>
<item name="something5_D"/>
<item name="something5_E"/>
<!-- Footer - for-each sorting -->
<item name="something6_F"/>
<item name="something6_G"/>
<item name="something6_H"/>
</items>
Initially, items order is random.
The first sort should create those three different parts: put everything that is header on the top, everything that is footer on the bottom, and keep everything else where it is. I can determine if something should go in the header, in the body or in the footer looking at its ending (the value after the last underscore).
The second sort should work differently on each of those parts (per-element sorting for header and footer, per-group sorting for body).
I know how I can sort the header, the body and the footer (thanks to this answer), but not how to move them and sort them with different algorithms.
Assuming you have a template that matches items then it's just a case of separating the item elements into three groups, which you say you can do via the endings:
<xsl:variable name="headerItems" select="item[
some $suf in ('_A', '_B', '_C') satisfies ends-with(#name, $suf)]" />
<xsl:variable name="footerItems" select="item[
some $suf in ('_F', '_G', '_H') satisfies ends-with(#name, $suf)]" />
<xsl:variable name="bodyItems"
select="item except ($headerItems | $footerItems)" />
and then handling the three groups in sequence however you need to.

How to find ancestor-or-self that is a child of an element with particular attribute?

I'm working with a very generic XML structure, where everything is an item (well everything relevant to this question anyway).
Based on knowing the item element I'm currently on and the item element that is the parent of the node I'm looking for, I need to find an item. I have a working xpath, but it's fairly resource intensive and I'm looking for something more elegant and cheaper.
The item key=a node is the parent of the element I'm looking for (though it's not actually a child of the document root)
XML:
<root>
<item key="a">
<item key="b">
<item key="c">
<item key="d"/>
</item>
</item>
<item key="e">
<item key="f">
<item key="g"/>
</item>
</item>
</item>
</root>
The actual XML is much deeper and with far more branching.
So for instance, if I'm on the item with key=g, e or f I need to return the item with key=e. If I'm on the item with key b,c or d I need to return the item with key=b.
I'm using this xpath, which is working, but going up and then back down the ancestor-descendant axis seems a far longer trip than I need.
current()
/ancestor-or-self::item[#key='a']
/item[descendant-or-self::* = current()]
Is there a simpler way of doing this, bearing in mind that I only know 1) the node I'm on and 2) the key attribute of the parent of the node I'm looking for?
Just for detail's sake: The XML is Sitecore generated, I'm not actually using the current() function, I'm using the sc_currentitem parameter to set the start node I need to begin processing at.
Thanks in advance.
Use:
ancestor-or-self::*[parent::item[#key='a']]