XQuery - merge XML-data
Added by Anonymous over 15 years ago
Legacy ID: #7410530 Legacy Poster: NickDiamond (nickdiamond_80)
Hi, I am searching for a possibility to reduce complexity of my XML results. I want to merge equal XML-elements. Here an example what I want to do : I have this result : <document> <webuser> <user01> <Content>1</Content> </user01> </webuser> <webuser> <user02> <Content>2</Content> </user02> </webuser> </document> But it would look better this way : <document> <webuser> <user01> <Content>1</Content> </user01> <user02> <Content>2</Content> </user02> </webuser> </document> Of course there are more possibilities how the final result could look like, but thats not the point ;) Has someone an idea how to do this ? (this is just an easy example. My other xml-results are more complex, so there should be a "generic" way...) Thanks, ND
Replies (8)
Please register to reply
RE: XQuery - merge XML-data - Added by Anonymous over 15 years ago
Legacy ID: #7410545 Legacy Poster: Michael Kay (mhkay)
Firstly, this forum is for Saxon-specific questions. General coding questions about XQuery would be better posted on talk @ x-query.com Secondly, I'm afraid your example is not really enough to explain the problem. Do you always want to merge adjacent webuser elements, or only those than meet certain conditions? Do you want to merge all adjacent elements sharing the same name, or only webuser elements? Finally, there are some problems that are easier to solve with XQuery and some that are easier to solve with XSLT. This is definitely one of the latter.
RE: XQuery - merge XML-data - Added by Anonymous over 15 years ago
Legacy ID: #7410584 Legacy Poster: NickDiamond (nickdiamond_80)
<<<Firstly, this forum is for Saxon-specific questions. General coding questions about XQuery would be better posted on talk @ x-query.com >>> Sry, I tried "talk@x-query.com", but I didnt really understand how use it... <<<Secondly, I'm afraid your example is not really enough to explain the problem. Do you always want to merge adjacent webuser elements, or only those than meet certain conditions? Do you want to merge all adjacent elements sharing the same name, or only webuser elements?>>> "merge all adjacent elements sharing the same name" is how I could describe it (if my english wasnt that bad). I try it with my own words : I want to merge elements with the same name. I also want to merge their child-elements with the same name: for example (doesnt make a lot of sense, but...): <document> <webuser> <user> <xy>1</xy> </user> </webuser> <webuser> <user> <xy>2</xy> </user> </webuser> </document> -> <document> <webuser> <user> <xy>1</xy> <xy>2</xy> </user> </webuser> </document> My english is not good enough to explain, but maybe you could image that the data you have a flatfile that looks like this, and you want as a XML: ... Peter#Jackson#LosAngeles#Car#Ferrari Peter#Jackson#LosAngeles#Car#Porsche Peter#Jackson#NewYork#Car#PorscheCayenne ... ... How would this data look as a XML-File? Maybe ; <Peter> <Jackson> <LosAngeles> <Car>Ferrari</Car> <Car>Porsche</Car> </LosAngeles> <NewYork> <Car>PorscheCayenne</Car> </NewYork> </Jackson> </Peter> So maybe you see how my result should be reduced... <<<Finally, there are some problems that are easier to solve with XQuery and some that are easier to solve with XSLT. This is definitely one of the latter>>> Yes, but I would prefer to go only with XQuery...
RE: XQuery - merge XML-data - Added by Anonymous over 15 years ago
Legacy ID: #7410624 Legacy Poster: Michael Kay (mhkay)
Well, here's the XSLT solution: <xsl:template match="*"> <xsl:for-each-group select="child::node()" group-adjacent="node-name()"> <xsl:copy> <xsl:apply-templates select="current-group()/child::node()"/> </xsl:copy> </xsl:for-each-group> </xsl:template> I'm afraid the XQuery equivalent is just too horrible to contemplate - you have to do the recursive descent of the tree "by hand" using a recursive user-defined function, and you have to do the grouping by hand using another layer of recursion. I'm afraid if you want help driving screws, I'm going to show you how to do it with a screwdriver; if you prefer to use a hammer for the job, that's your problem.
RE: XQuery - merge XML-data - Added by Anonymous over 15 years ago
Legacy ID: #7411837 Legacy Poster: NickDiamond (nickdiamond_80)
Thank you. The answer that it is almost impossible to have a good XQuery-Solution for that case, is ok for me. Because with that I can show the restrictions of XQuery, and that XQuery is not the answer for every case...
RE: XQuery - merge XML-data - Added by Anonymous over 15 years ago
Legacy ID: #7411934 Legacy Poster: Jesper Tverskov (jesper_tverskov)
I was just wondering if it is possible to use Saxon's extension function, saxon:for-each-group(), to solve the problem? Available in Saxon SA only. http://www.saxonica.com/documentation/extensions/functions/for-each-group.html Cheers, Jesper
RE: XQuery - merge XML-data - Added by Anonymous over 15 years ago
Legacy ID: #7411959 Legacy Poster: Michael Kay (mhkay)
saxon:for-each-group only handles value-based grouping (group-by), it doesn't handle group-adjacent. I think that in XQuery 1.0 the grouping would have to be done by sibling recursion - which is not impossible, of course, it just requires a bit of careful thought.
RE: XQuery - merge XML-data - Added by Anonymous over 15 years ago
Legacy ID: #7416509 Legacy Poster: NickDiamond (nickdiamond_80)
I am also sure that it is possible, but it starts to hurt my brain :D There ware so many possibilities how the input-data can look like...
RE: XQuery - merge XML-data - Added by Anonymous over 15 years ago
Legacy ID: #7460356 Legacy Poster: Willem van Heerde (wheerde)
Hello ND, I saw your problem and a small solution is possible in xquery, see the code: declare function local:joinelement($seq as element()) as element() { if ($seq) then if ((node-name($seq[1]) = node-name($seq[2])) and ($seq[1]/)) then local:joinelement( (element {node-name($seq[1])} { ($seq[1]/,$seq[2]/) } ,$seq[position() >= 3]) ) else (element {node-name($seq[1])} { ($seq[1][empty()]/text(),local:joinelement($seq[1]/*)) } ,local:joinelement($seq[position()!=1])) else () }; Call this function with something like local:joinelement(doc('yourxmlfile.xml')/element()) I can also give you a recursive version if you like, this is somewhat larger; about 10 more lines. Hope you can use it, Willem.
Please register to reply