Subject: Re: [xsl] Apply-templates - how to omit top level element tags? From: Jon Gorman <jonathan.gorman@xxxxxxxxx> Date: Thu, 8 Sep 2005 09:36:28 -0500 |
On 9/7/05, Mike Schinkel <mikes@xxxxxxxxx> wrote: > >> Plenty of ways to do this and it's hard to tell advise any particular > method without knowing more about your XML.templates and your style. > > Thanks. What do you mean by "style?" Can you quantify this, or is it > just a subjective thing? > To some extent it is a subjective thing. With this problem there are a lot of ways to do it. I gave three possibilities if I recall correctly, most of the others recommended the same things. You also seem to be talking about a couple of different problems, but all of them fairly basic. One is the use of the "element name" in different contexts. The more powerful way to deal with this is modes. If the structure is simple enough, you can just match further up the tree as Michael Kay just sent. As for the trademark, a simple match should do the trick, something like what you had in your output below. The problem is that you need to understand how the tree is processed, some of the built-in rules and XPath. There is generally two recommend "approaches" to creating stylesheets, pull & push, although I tend to use a middle road. Pulling relies heavily on value-of and for-each loops, building a document by grabbing nodes from the source xml document. It doesn't use apply-templates. It is tended to be used with more data-centric outputs where the input is pretty predictable. I find a lot of newbies end up using this heavily because they get confused about the processing model and the built-in rules. Push tends to rely on the processing model, using apply-templates. To process different parts of a document that might have similar elements (imagine a metadata part of the document vs the actual document) many use modes. It is used primarily when working with "narrative" documents due to their unpredictable nature. Remember apply-templates essentially says find any templates that match my select (or by default the children nodes of the current node) and apply them. WIthout knowning more about the type of documents you are processing and how your other templates are dealing with the processing model it's hard to give advice on the snippets. I've seen cases where people use a purely pull model in the <xsl:template match="/"></xsl:template>, but ask something that would lead one to believe it was more of a push model. When someone suggests a template that would convert the particular element how they want, it doesn't work because that element is never actually seen by the processing model. > Also, why is it not possible to be able to output: > > FooXXX > > When you start with > > <Name>Foo<myns:MyX></Name> > > Where the XSL has this: > > <xsl:template match="myns:MyX">XXX</xsl:template> It is possible to do this. Without seeing your stylesheet I have no clue why it doesn't work for you. Possibilities include, but are not limited to: namespace is not correct, so it never actually sees any of the nodes with the myns prefix, you have a template that matches the Name terminates the processing at that node (think base case), perhaps you just never call that template, or even the input is literally how you describe it and invalid XML and never even reaches the XSLT processor and is failing at the parser (is it really <mnsy:MyX> and not <mnsy:MyX />). If the namespace is set up correctly (look through the archives) you should be able to have just that template in a stylesheet and that with the default rules will produce fooXXX. It worked fine for me. > > I either get: > > <Name>FooXXX</Name> Ah, is this output changing every time you run the script, or did you tinker with the stylesheet and didn't tell us ;). Looks like you're using copy somewhere. > > Or just: > > Foo Namespace issues? Just using <xsl:value-of />? > > But not what I want, which is: > > FooXXX > > Why do I have to write a specific template to accomplish this? Ya don't. >In the > case above I want to output the value contained in <Name> that way only > once, but I also want the write of the XML to be able to embed other > references into it that I can parse with apply-templates. So use the default rules. Remember, your Name node in XPath can be seen as a tree, rep in crude ASCII form below Parent and current node - Name (element node): Child - Foo (text node) Child - myns:MyX (element node) If you process the Name node and do "value-of", you're asking for the string representation of the Name node, or the string-value as per the XPath (this is all in the specs, I'm assuming you are using XSLT 1.0 instead of XSLT 2.0) for element nodes "The string-value of an element node is the concatenation of the string-values of all text node descendants of the element node in document order." So it only selects the text nodes for the value. What it really sounds like what you want is not the value-of the Name node, but of the text nodes and a special value for the myns:MyX, so don't try putting out a value in the Name template. That's my only guess at what you did since you told us the results of your efforts but no clue as to what you actually did to cause it. so lets say you have something like Parent and current node - Name (element node): Child - Foo (text node) Child - myns:MyX (element node) Child - bar (Text node) ie <Name>Foo<myns:MyX />bar</Name> If you do <xsl:template match="Name"> <xsl:value-of select="."/> <xsl:apply-templates /> </xsl:templates> You're going to get some funky output. Off the top of my head probably something like FoobarXXXFoobar (you "pull" the value, then the "push" will match both the text nodes and the template for myns:MyX) However, if you just use the template you gave, you'll get FooXXXbar just like you want. > Having to create a template for a single case is like having to write a > function in Java called Add37(x) simply to add 37 to the variable "x" in > only one place in the code. Why can't I just do it inline rather than > have to worry about logic in two places and also worry about potential > sideaffects or name collisions? Is it because XSL simply doesn't provide > such a capability? Ummm, the entire point of XSL is to be as side-effect free as possible. Name collision can be problematic, but no more than it always is. In fact, XSLT gives you lots of ways to handle name collisions such as modes, choose blocks with XPath tests, and simply controlling how processing matches the templates. I'm not sure how you are even causing "side-effects". It looks more like you have some other templates in your stylesheet but don't know what they are doing because you don't understand the processing model. This isn't really a side effect in the sense you call count(foo) and it actually increments foo by one. Ah, a long email, but to essentially sum it up, check for namespace problems. Perhaps show us some more snippets of the stylesheet. Skim through the XPath spec so you actually understand what templates are being matched. It sounds like you have a identity transform template somewhere but you don't want it. You seem to be heading in the right direction, but it feels like you're playing around with too large of a stylesheet that you don't understand. Think of this as really, really complex induction proof. That's probably more advice then you wanted, but again, give us some more info, or better yet go skim through the actual specs for the language and play around with some simpler samples. Jon Gorman
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
RE: [xsl] Apply-templates - how to , Mike Schinkel | Thread | RE: [xsl] Apply-templates - how to , Wendell Piez |
Re: [xsl] note: Handling '&nbsp, David Carlisle | Date | Re: [xsl] How to do this without up, JBryant |
Month |