Suppose I have some XML like this:
<section name="SampleSection">
<item name="ScoredItem1">
<attributes>
<scored data_type="boolean" value="true"/>
</attributes>
</item>
<item name="UnscoredItem1">
<attributes>
<scored data_type="boolean" value="false"/>
</attributes>
</item>
<item key="(3272fbb5:22)" name="ScoredItem2">
<attributes>
<scored data_type="boolean" value="true"/>
</attributes>
</item>
</section>
Now, I know, using XSLT, I can count the items that have a scored attribute like this:
<xsl:variable name="scoredItems" select="item/attributes/scored"/>
<xsl:value-of select="count($scoredItems)"/>
This will give me a value of 3, of course.
Suppose I only want to count those items for which scored is true. How do I do that using XSLT? (This should return a value of 2 for this example.
Do it like this:
<xsl:variable name="scoredItems"
select=
"item/attributes/scored[#value='true']"/>
Related
I am trying to access a value from the next node inside a for loop in XSLT.
The XML source is :
<?xml version="1.0" encoding="UTF-8"?>
<tree>
<parent>
<id>1</id>
<child>
<effective_date>01-09-2019</effective_date>
<hours>10</hours>
<dept>1</dept>
</child>
<child>
<effective_date>01-10-2019</effective_date>
<hours>20</hours>
<dept>1</dept>
</child>
<child>
<effective_date>01-10-2019</effective_date>
<class>A</class>
</child>
</parent>
<parent>
<id>2</id>
<child>
...
</child>
<child>
..
</child>
</parent>
</tree>
The desired output is that I want the next child node's Effective_date value in first validUntil tag in result like below :
<?xml version="1.0" encoding="UTF-8"?>
<employees>
<departments>
<department>
<code>1</code>
<weeklyHours>10</weeklyHours>
<validFrom>2019-09-09</validFrom>
<validUntil>2019-10-01</validUntil
</department>
<department>
<code>1</code>
<weeklyHours>20</weeklyHours>
<validFrom>2019-10-01</validFrom>
<validUntil/>
</department>
</departments>
</employees>
In my original xslt, I am inside a for loop, which I am entering conditionally based on whether a child element has change in hours or not. So this has to be accessed inside a for loop.
If the xsl:for-each is iterating over sibling elements, then you can get the next element using following-sibling::*
If you are iterating over an arbitrary sequence $SEQ, then you can get the next element using:
XSLT 2.0: subsequence($SEQ, position()+1, 1)
XSLT 1.0: <xsl:variable name="p" select="position()"/><xsl:.... select="$SEQ[$p+1]"/>
Don't make the mistake of using $SEQ[position()+1] - the value of position() changes within a predicate.
I am trying to retrieve only distinct values of an element. This is my XML:
<LaunchedMeterClass id="584e348b-2a06-42d0-a858-b8909f579238-St-4M-Template-Standard-cF">
<property key="ClusterContractUUID" value="c2cebd90-9265-4cea-8018-0aac6efcced2"/>
<property key="MeterClassTypeCode" value="cF"/>
</LaunchedMeterClass>
<LaunchedMeterClass id="584e348b-2a06-42d0-a858-b8909f579238-St-4M-Template-Standard-cE">
<property key="ClusterContractUUID" value="c2cebd90-9265-4cea-8018-0aac6efcced2"/>
<property key="MeterClassTypeCode" value="cE"/>
</LaunchedMeterClass>
<LaunchedMeterClass id="584e348b-2a06-42d0-a858-b8909f579238-St-4M-Template-Standard-cC">
<property key="ClusterContractUUID" value="d0c9f440-172c-49ad-9b95-cddce23f16fa"/>
<property key="MeterClassTypeCode" value="cC"/>
</LaunchedMeterClass>
<LaunchedMeterClass id="584e348b-2a06-42d0-a858-b8909f579238-St-4M-Template-Standard-cD">
<property key="ClusterContractUUID" value="d0c9f440-172c-49ad-9b95-cddce23f16fa"/>
<property key="MeterClassTypeCode" value="cD"/>
</LaunchedMeterClass>
I want to create an XPath to get only those "LaunchedMeterClass" nodes having an unique value for <property key="ClusterContractUUID">. At the moment, I am using the following:
<xsl:for-each select="./descendant::LaunchedMeterClass">
<xsl:choose>
<xsl:when test="./property/#key='ClusterContractUUID'">
<contract-type>
<property>
<xsl:attribute name="key">ClusterContractUUID</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="./property[#key='ClusterContractUUID']/#value"/>
</xsl:attribute>
</property>
</contract-type>
</xsl:when>
<xsl:otherwise>
<contract-type>
<property>
<xsl:attribute name="key">contractTypeCategory</xsl:attribute>
</property>
</contract-type>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
But this gives me all the elements including duplicates:
<contract-type>
<property key="ClusterContractUUID" value="c2cebd90-9265-4cea-8018-0aac6efcced2"/>
</contract-type>
<contract-type>
<property key="ClusterContractUUID" value="c2cebd90-9265-4cea-8018-0aac6efcced2"/>
</contract-type>
<contract-type>
<property key="ClusterContractUUID" value="d0c9f440-172c-49ad-9b95-cddce23f16fa"/>
</contract-type>
<contract-type>
<property key="ClusterContractUUID" value="d0c9f440-172c-49ad-9b95-cddce23f16fa"/>
</contract-type>
How can I write an XPath which gives only distinct values? My desired output is:
<contract-type>
<property key="ClusterContractUUID" value="c2cebd90-9265-4cea-8018-0aac6efcced2"/>
</contract-type>
<contract-type>
<property key="ClusterContractUUID" value="d0c9f440-172c-49ad-9b95-cddce23f16fa"/>
</contract-type>
Thank you in advance for your help!
Try this:
XML:
<root>
<LaunchedMeterClass id="584e348b-2a06-42d0-a858-b8909f579238-St-4M-Template-Standard-cF">
<property key="ClusterContractUUID" value="c2cebd90-9265-4cea-8018-0aac6efcced2"/>
<property key="MeterClassTypeCode" value="cF"/>
</LaunchedMeterClass>
<LaunchedMeterClass id="584e348b-2a06-42d0-a858-b8909f579238-St-4M-Template-Standard-cE">
<property key="ClusterContractUUID" value="c2cebd90-9265-4cea-8018-0aac6efcced2"/>
<property key="MeterClassTypeCode" value="cE"/>
</LaunchedMeterClass>
<LaunchedMeterClass id="584e348b-2a06-42d0-a858-b8909f579238-St-4M-Template-Standard-cC">
<property key="ClusterContractUUID" value="d0c9f440-172c-49ad-9b95-cddce23f16fa"/>
<property key="MeterClassTypeCode" value="cC"/>
</LaunchedMeterClass>
<LaunchedMeterClass id="584e348b-2a06-42d0-a858-b8909f579238-St-4M-Template-Standard-cD">
<property key="ClusterContractUUID" value="d0c9f440-172c-49ad-9b95-cddce23f16fa"/>
<property key="MeterClassTypeCode" value="cD"/>
</LaunchedMeterClass>
</root>
XSLT2.0
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="root">
<xsl:for-each select="distinct-values(descendant::property[#key='ClusterContractUUID']/#value)">
<contract-type>
<property>
<xsl:attribute name="key">ClusterContractUUID</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="."/>
</xsl:attribute>
</property>
</contract-type>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Result:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<contract-type>
<property key="ClusterContractUUID" value="c2cebd90-9265-4cea-8018-0aac6efcced2"/>
</contract-type>
<contract-type>
<property key="ClusterContractUUID" value="d0c9f440-172c-49ad-9b95-cddce23f16fa"/>
</contract-type>
</root>
Edit:
Edited to get following-sibling values. In above XSLT, template match is # attributes side, instead of that if template match at elements, we can access the other siblings, ancestors, descendants, etc, easily.
XSLT:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy><xsl:apply-templates select="#* | node()"/></xsl:copy>
</xsl:template>
<xsl:template match="root">
<root>
<xsl:for-each select="descendant::property[#key='ClusterContractUUID'
and not(#value=preceding::property[#key='ClusterContractUUID']/#value)]">
<contract-type>
<xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy>
<xsl:apply-templates select="following-sibling::property"/>
</contract-type>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
You can perhaps try exslt's set:distinct:
http://exslt.org/set/functions/distinct/
There's an example at the bottom. Your mileage may vary.
This is generally known as "grouping".
In XSLT 2.0, use the <xsl:for-each-group> construct.
In XSLT 1.0, use "Muenchian grouping" - you'll find that in your favourite XSLT textbook, or in online resources.
If you really need to do it in XPath rather than XSLT (your question is unclear) the best you can do is the XPath 2.0 distinct-values() function - there's nothing in XPath 1.0 that will help you much.
I'm trying to create a program using gtkmm3 and the Application::set_menubar method. I can create the menu, but when I run the program, all of the items in the menus are greyed out. I have scoured both the glibmm and glib libraries looking for ways to enable (and later disable/hide) menu items, and I cannot find any function or method to do it. How do I fix this?
I'm compiling with:
g++ -std=c++0x -o program program.cpp `pkg-config --cflags --libs gtkmm-3.0`
Code code is as follows:
// vim:set ai et shiftwidth=4 softtabstop=4 :
#include <gtkmm.h>
#include <glibmm.h>
#include <giomm/menulinkiter.h>
class ApplicationMain{
private:
Glib::RefPtr<Gtk::Application> app;
Glib::RefPtr<Gio::Menu> mnuMenu;
/// Builds menu and puts menu actions into the application's action map
void createMenu();
/// Recursive method that iterates over the supplied MenuModel and
/// extracts actions into the application's action map
void extractMenuActions(const Glib::RefPtr<Gio::MenuModel> &model);
public:
ApplicationMain(int argc, char **argv);
~ApplicationMain();
int run();
};
using namespace std;
/// Container for menu xml data
struct MenuStringContainer{
static const char *string;
};
/// Builds menu and puts menu actions into the application's action map
void ApplicationMain::createMenu(){
// Build menu from xml data
Glib::RefPtr<Gtk::Builder> builder = Gtk::Builder::create_from_string(MenuStringContainer::string);
mnuMenu = Glib::RefPtr<Gio::Menu>::cast_dynamic(builder->get_object("menubar"));
// Extract actions from menu model and add them to our action map
extractMenuActions(Glib::RefPtr<Gio::MenuModel>::cast_static(mnuMenu));
}
void ApplicationMain::extractMenuActions(const Glib::RefPtr<Gio::MenuModel> &model){
// Get the number of items in this menu model
gint count = g_menu_model_get_n_items(model->gobj());
// Iterate over the items in this model
for(gint i = 0; i < count; i++){
// Iterate over and recurse into the links in this menu model item
auto iter = model->iterate_item_links(i);
while(iter->next()){
extractMenuActions(iter->get_value());
}
try{
// Get the action for this item. Throws std::bad_cast if the cast can't be made
Glib::Variant<Glib::ustring> act = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring>>(
model->get_item_attribute(i, Gio::MENU_ATTRIBUTE_ACTION, Glib::Variant<Glib::ustring>::variant_type())
);
// If this action is valid, get the action name and add it to the action map
if(act.gobj() != nullptr){
Glib::ustring actName = act.get();
app->add_action(Gio::SimpleAction::create(actName));
}
} catch(std::bad_cast &){
}
}
}
ApplicationMain::ApplicationMain(int argc, char **argv){
app = Gtk::Application::create(argc, argv, "com.angellistaliuu.jaguar.Chummer5");
chdir(Gio::File::create_for_commandline_arg(argv[0])->get_basename().c_str());
}
ApplicationMain::~ApplicationMain(){
}
int ApplicationMain::run(){
if(app->register_application()){
createMenu();
app->set_menubar(mnuMenu);
{
Gtk::ApplicationWindow *frm = new Gtk::ApplicationWindow();
// Allow pointer to be unreferenced when this scope ends
Glib::RefPtr<Gtk::ApplicationWindow> frmPtr(frm);
app->run(*frm);
}
} else {
app->activate();
}
}
int main(int argc, char **argv){
ApplicationMain appMain(argc, argv);
return appMain.run();
}
// XML data for application menu
const char *MenuStringContainer::string = R"rawstring(
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="menubar">
<submenu>
<attribute name="label">_File</attribute>
<section>
<item>
<attribute name="label">_New Character</attribute>
<attribute name="action">file.newchar</attribute>
</item>
<item>
<attribute name="label">New _Critter</attribute>
<attribute name="action">file.newcrit</attribute>
</item>
<item>
<attribute name="label">_Open</attribute>
<attribute name="action">file.open</attribute>
</item>
</section>
<section>
<item>
<attribute name="label">_Print</attribute>
<attribute name="action">file.print</attribute>
</item>
<item>
<attribute name="label">Print _Multiple</attribute>
<attribute name="action">file.printmultiple</attribute>
</item>
<item>
<attribute name="label">Print Setup</attribute>
<attribute name="action">file.printsetup</attribute>
</item>
</section>
<section id="mru">
<item>
<attribute name="label">[StickyMRU0]</attribute>
<attribute name="action">file.smru0</attribute>
</item>
<item>
<attribute name="label">[StickyMRU1]</attribute>
<attribute name="action">file.smru1</attribute>
</item>
<item>
<attribute name="label">[StickyMRU2]</attribute>
<attribute name="action">file.smru2</attribute>
</item>
<item>
<attribute name="label">[StickyMRU3]</attribute>
<attribute name="action">file.smru3</attribute>
</item>
<item>
<attribute name="label">[StickyMRU4]</attribute>
<attribute name="action">file.smru4</attribute>
</item>
<item>
<attribute name="label">[StickyMRU5]</attribute>
<attribute name="action">file.smru5</attribute>
</item>
<item>
<attribute name="label">[StickyMRU6]</attribute>
<attribute name="action">file.smru6</attribute>
</item>
<item>
<attribute name="label">[StickyMRU7]</attribute>
<attribute name="action">file.smru7</attribute>
</item>
<item>
<attribute name="label">[StickyMRU8]</attribute>
<attribute name="action">file.smru8</attribute>
</item>
<item>
<attribute name="label">[StickyMRU9]</attribute>
<attribute name="action">file.smru9</attribute>
</item>
<item>
<attribute name="label">[MRU0]</attribute>
<attribute name="action">file.mru0</attribute>
</item>
<item>
<attribute name="label">[MRU1]</attribute>
<attribute name="action">file.mru1</attribute>
</item>
<item>
<attribute name="label">[MRU2]</attribute>
<attribute name="action">file.mru2</attribute>
</item>
<item>
<attribute name="label">[MRU3]</attribute>
<attribute name="action">file.mru3</attribute>
</item>
<item>
<attribute name="label">[MRU4]</attribute>
<attribute name="action">file.mru4</attribute>
</item>
<item>
<attribute name="label">[MRU5]</attribute>
<attribute name="action">file.mru5</attribute>
</item>
<item>
<attribute name="label">[MRU6]</attribute>
<attribute name="action">file.mru6</attribute>
</item>
<item>
<attribute name="label">[MRU7]</attribute>
<attribute name="action">file.mru7</attribute>
</item>
<item>
<attribute name="label">[MRU8]</attribute>
<attribute name="action">file.mru8</attribute>
</item>
<item>
<attribute name="label">[MRU9]</attribute>
<attribute name="action">file.mru9</attribute>
</item>
</section>
<section>
<item>
<attribute name="label">E_xit</attribute>
<attribute name="action">file.exit</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label">_Tools</attribute>
<section>
<item>
<attribute name="label">_Dice Roller</attribute>
<attribute name="action">tools.roller</attribute>
</item>
</section>
<section>
<item>
<attribute name="label">_Options</attribute>
<attribute name="action">tools.options</attribute>
</item>
<item>
<attribute name="label">Check for Updates</attribute>
<attribute name="action">tools.updates</attribute>
</item>
<item>
<attribute name="label">Omae</attribute>
<attribute name="action">tools.omae</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label">_Windows</attribute>
<section>
<item>
<attribute name="label">_New Window</attribute>
<attribute name="action">windows.new</attribute>
</item>
<item>
<attribute name="label">C_lose All</attribute>
<attribute name="action">windows.closeall</attribute>
</item>
</section>
<section id="windowlist">
</section>
</submenu>
<submenu>
<attribute name="label">_Help</attribute>
<section>
<section>
<item>
<attribute name="label">Chummer Wiki</attribute>
<attribute name="action">help.chummerwiki</attribute>
</item>
</section>
<item>
<attribute name="label">_Revision History</attribute>
<attribute name="action">help.revisionhistory</attribute>
</item>
<item>
<attribute name="label">_Dumpshock Thread</attribute>
<attribute name="action">help.dumpshockthread</attribute>
</item>
<item>
<attribute name="label">_About...</attribute>
<attribute name="action">help.about</attribute>
</item>
</section>
</submenu>
</menu>
</interface>
)rawstring"; //"(
You are calling register_application() manually, rather than letting GtkApplication/GApplication do that for you. You probably did that to avoid this warning, which I think is the main clue, because the gtkmm examples never need to do that:
(a.out:24959): Gtk-CRITICAL **: gtk_application_set_menubar: assertion 'g_application_get_is_registered (G_APPLICATION (application))' failed
I have reduced your test case down to a simpler test case with no class definition and no use of GtkBuilder, and now I guess the problem is probably that you are adding these actions, or the menu, too early, though I'm not sure exactly what is not yet set up properly. I can post that test case here, if you like.
For instance, this example works, but notice that it adds the menu and its actions in the derived Gtk::Application's on_startup():
https://git.gnome.org/browse/gtkmm-documentation/tree/examples/book/application/app_and_win_menus/exampleapplication.cc#n32
Deriving a Gtk::Application is the more correct structure anyway, allowing the app to do the right thing at the right time. GtkApplication is a rather awkward and unforgiving API, in my opinion, so I wouldn't stray from the path.
Incidentally, it's also rather confusing to define an ApplicationMain class that doesn't derive from Gtk::Application. And you should avoid using RefPtr<> with a widget (Gtk::ApplicationWindow) class. You should never need to do any referencing or unreferencing of widgets in your application code.
I'm new to WSO2 Data Services Server and I trying to figure out how to get complex element types working correctly with the web scraper. Using the interface I seem to be able to define the object, but I'm not sure how to use it once it is defined. Below is the Data Service XML...
<data name="ComplexTypeExample">
<description>A Description</description>
<config id="GetPrices">
<property name="web_harvest_config">./samples/resources/GetPrices.xml</property>
</config>
<query id="getSonyPrices" useConfig="GetPrices">
<scraperVariable>priceInfoSony</scraperVariable>
<result element="CameraInfo" rowName="Record">
<element column="Pic" name="Pic" xsdType="string"/>
<element column="Desc" name="Desc" xsdType="string"/>
<element name="Inventory" namespace="">
<element name="Item" namespace="">
<element column="Grade" name="Grade" xsdType="string"/>
<element column="Price" name="Price" xsdType="string"/>
</element>
</element>
</result>
</query>
<operation name="getSonyPricesOperation">
<description>Gets prices of KM/Sony cameras</description>
<call-query href="getSonyPrices"/>
</operation>
</data>
What I am trying to do is figure out how to get the Inventory element to be an array of Item types. Something like this...
<Record>
<Pic>Camera.jpg</Pic>
<Desc>A camera made by some company</Desc>
<Inventory>
<Item>
<Grade>Good</Grade>
<Price>$200</Price>
</Item>
<Item>
<Grade>Not So Good</Grade>
<Price>$100</Price>
</Item>
<Item>
<Grade>Broken</Grade>
<Price>$10</Price>
</Item>
</Inventory>
</Record>
Can anyone provide some hints as to where I'm going wrong?
Looks like you have done your complex element mapping correctly according to your result set .. Are you having trouble scraping the values? If so you have to provide us with the scraping configuration, and also you have to write the xslt file also according to your complex elements.
Please refer the following guide for web scraping
Input XML
<?xml version="1.0" encoding="UTF-8" ?>
<Z_RFC_SP_POTEXT_OUT >
<ZMPO_TXT>
<item>
<LIFNR>0009002008</LIFNR>
<ZPOTEXT1>BSE-TSE Statement document is accpeted by sup3#spp2.com on 2010-04-12</ZPOTEXT1>
<ZPOTEXT2 />
<FLAG />
</item>
<item>
<LIFNR>0009002008</LIFNR>
<ZPOTEXT1>Ist Part</ZPOTEXT1>
<ZPOTEXT2 />
<FLAG />
</item>
<item>
<LIFNR>0009002008</LIFNR>
<ZPOTEXT1>2nd Part</ZPOTEXT1>
<ZPOTEXT2 />
<FLAG />
</item>
<item>
<LIFNR>0009000013</LIFNR>
<ZPOTEXT1>vComments for Obj 1hkshkshdiswyidswyidyswidysiysiysskhskchskhckchk</ZPOTEXT1>
<ZPOTEXT2 />
<FLAG />
</item>
<item>
<LIFNR>0009000017</LIFNR>
<ZPOTEXT1>vComments for Obj 1hkshkshdiswyidswyidyswidysiysiysskhskchskhckchk</ZPOTEXT1>
<ZPOTEXT2 />
<FLAG />
</item>
<item>
<LIFNR>0009000017</LIFNR>
<ZPOTEXT1>1st part</ZPOTEXT1>
<ZPOTEXT2 />
<FLAG />
</item>
<item>
<LIFNR>0009000017</LIFNR>
<ZPOTEXT1>2nd part</ZPOTEXT1>
<ZPOTEXT2 />
<FLAG />
</item>
<item>
<LIFNR>0009000022</LIFNR>
<ZPOTEXT1>INCLUDE ZPTP_TERMS_AND_CONDITIONS_2003 OBJECT TEXT ID ST</ZPOTEXT1>
<ZPOTEXT2 />
<FLAG />
</item>
<item>
<LIFNR>0009000026</LIFNR>
<ZPOTEXT1>INCLUDE ZPTP_TERMS_AND_CONDITIONS_2003 OBJECT TEXT ID ST</ZPOTEXT1>
<ZPOTEXT2 />
<FLAG />
</item>
</ZMPO_TXT>
</Z_RFC_SP_POTEXT_OUT>
I am looking for the output
<?xml version="1.0" encoding="UTF-8" ?>
<Z_RFC_SP_POTEXT_OUT >
<ZMPO_TXT>
<item>
<LIFNR>0009002008</LIFNR>
<ZPOTEXT1>BSE-TSE Statement document is accpeted by sup3#spp2.com on 2010-04-12 Ist Part 2nd Part</ZPOTEXT1>
<ZPOTEXT2 />
<FLAG />
</item>
<item>
<LIFNR>0009000013</LIFNR>
<ZPOTEXT1>vComments for Obj 1hkshkshdiswyidswyidyswidysiysiysskhskchskhckchk</ZPOTEXT1>
<ZPOTEXT2 />
<FLAG />
</item>
<item>
<LIFNR>0009000017</LIFNR>
<ZPOTEXT1>vComments for Obj 1hkshkshdiswyidswyidyswidysiysiysskhskchskhckchk 1st part 2nd part</ZPOTEXT1>
<ZPOTEXT2 />
<FLAG />
</item>
<item>
<LIFNR>0009000022</LIFNR>
<ZPOTEXT1>INCLUDE ZPTP_TERMS_AND_CONDITIONS_2003 OBJECT TEXT ID ST</ZPOTEXT1>
<ZPOTEXT2 />
<FLAG />
</item>
<item>
<LIFNR>0009000026</LIFNR>
<ZPOTEXT1>INCLUDE ZPTP_TERMS_AND_CONDITIONS_2003 OBJECT TEXT ID ST</ZPOTEXT1>
<ZPOTEXT2 />
<FLAG />
</item>
</ZMPO_TXT>
</Z_RFC_SP_POTEXT_OUT>
How to do that using xslt?
looks like a Munchian Sort can help you further. if you group the items by <LIFNR>, you should be able to drop all text in a single node.