|
[XQuery Talk Mailing List Archive Home] [By Date] [By Thread] [By Subject] [By Author] [Recent Entries] [Reply To This Message] Selecting everything before and after path, but without duplicated leafsJ. Zhang zhangjunte at gmail.comMon Feb 11 14:52:11 PST 2008
On Feb 11, 2008 12:08 PM, Michael Kay <http://x-query.com/mailman/listinfo/talk> wrote: > Sorry, I started writing the function to return elements only and then > changed my mind. The type signature of the function should be "as node()*" > rather than "as element()". Michael, I got it working in XSLT with you tip. <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:strip-space elements="*"/> <xsl:output method="xml" encoding="ISO-8859-1" doctype-public="-//W3C//DTD HTML 4.0 Transitional//EN"/> <xsl:template match="*"> <xsl:copy> <xsl:copy-of select="@*" /> <xsl:apply-templates/> </xsl:copy> </xsl:template> <xsl:template match="/ead[1]/archdesc[1]/dsc[1]/c01[1]"> <SELECT /> <xsl:next-match/> </xsl:template> </xsl:stylesheet> However, I like XQuery more. :) Simply because I want to learn XQuery, I will ask one more question about this problem: The function looks like this: declare function local:processNode($e as node()) as node()* { typeswitch ($e) case element(c01) return <SELECT>{$e}</SELECT> case element() return element {name($e)} { for $c in $e/child::node() return local:processNode($c) } default return $e }; local:processNode(doc('file.xml')/*) Instead of matching the element name, I would like to match the entire path (node). In my case, I got the path "/ead[1]/archdesc[1]/dsc[1]/c01[1]". So the condition in the first case in the switch should be something else. I assume another extra function is needed. I already got a function that returns the path of the current node as a string: declare function local:getEADPath ( $node as node() ) as xs:string { let $pathelements := for $a in $node/ancestor-or-self::* return if ( name($a) = "ead" ) then "/ead[1]" else concat(name($a), "[" , count($a/preceding-sibling::*[name()=name($a)]) + 1, "]") return string-join( $pathelements, "/" ) }; Thanks, jz > Michael Kay > http://www.saxonica.com/ > > > -----Original Message----- > > From: J. Zhang [mailto:http://x-query.com/mailman/listinfo/talk] > > Sent: 11 February 2008 10:53 > > To: Michael Kay > > Cc: http://x-query.com/mailman/listinfo/talk > > Subject: Re: Selecting everything before and > > after path,but without duplicated leafs > > > > > On Feb 11, 2008 10:07 AM, Michael Kay <http://x-query.com/mailman/listinfo/talk> wrote: > > > > > what output would you like to see? > > > > > > > > I would like to preserve the original XML file, but only add an > > > > extra tag, so I would like to have this output: > > > > > > > > <ead> > > > > <banana/> > > > > <archdesc> > > > > <dsc> > > > > <c00/> > > > > <SELECT> > > > > <c01/> > > > > </SELECT> > > > > <c02/> > > > > </dsc> > > > > </archdesc> > > > > <custard/> > > > > </ead> > > > > > > In XSLT this is simply an identity template that copies all elements > > > unchanged: > > > > > > <xsl:template match="*"> > > > <xsl:copy><xsl:apply-templates/></xsl:copy> > > > </xsl:template> > > > > > > (or a variation of that if you need to handle attributes) > > > > > > supplemented by a template for the element you want to change: > > > > > > <xsl:template match="c01"> > > > <SELECT><xsl:next-match/></SELECT> > > > </xsl:template> > > > > > > (You can write a more elaborate match pattern if you need to be more > > > selective.) > > > > > > In XQuery you need to program the recursive descent by hand: > > > > > > declare function local:processNode($e as node()) as element() { > > > typeswitch ($e) { > > > case element(c01) return <SELECT>{$e}</SELECT> > > > case element() return > > > element {node-name($e)} {for $c in $e/child::node() return > > > local:processNode($c)} > > > default return $e > > > } > > > } > > > > > > local:processNode(doc('abc.xml')/*) > > > > > > plus a bit of extra logic if you need to handle attributes > > or namespaces. > > > > > > > Ok, this is what I am using: > > > > declare function local:processNode($e as node()) as element() > > { typeswitch ($e) > > case element(c01) > > return <SELECT>{$e}</SELECT> > > case element() > > return > > element {node-name($e)} { > > for $c in $e/child::node() return > > local:processNode($c) > > } > > default return $e > > }; > > > > local:processNode(doc('ead_10748500.xml')/*) > > > > ...but I am getting an error when using that function: > > > > XPTY0004: Required item type of result of function > > local:processNode() is element(); > > supplied value has item type text() > > Query processing failed: Run-time errors were reported > > > > The error message is obvious, but probably typecasting won't > > work here. > > > > Do you have any ideas? > > > > jz > > > > > > > Michael Kay > > > http://www.saxonica.com/ > > > > > > > > > > >
|
Purchase Stylus Studio Online Today!Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced! Download The World's Best XML IDE!Accelerate XML development with our award-winning XML IDE - Download a free trial today! Subscribe in XML format
|






