[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message] Re: Positional Grouping Problem - Add hierarchy to a f
Hi Tom, > Basically, I want to replace the <BeginFile> node, with a <File> > node. And then copy all elements between <BeginFile file="x"> and > its corresponding <EndFile file="x"> as subelements to this new > <File> node. Nesting <File> nodes if a second <BeginFile> node is > found before the corresponding <EndFile> node is found. For each > <BeginFile file="x"/>, there will always be a corresponding <EndFile > file="x"/> element. And the LineNum attribute is not that important, > but are in the original document, are valid, and can be used in the > solution. Thankfully, because you have filenames on both the <BeginFile> and <EndFile> elements, this isn't too hard to do... There are several approaches, but I find the easiest approach to be a recursive step-by-step approach. Basically, we're going to step through the elements in <LogFile> one by one. When we come across a <BeginFile> element, we'll create a <File> element. For the content of the <File> element, we'll process its following sibling, and for the part after the new <File> element, we'll jump on to the element after the matching <EndFile> element for the <BeginFile>. Because we need to jump from a <BeginFile> element to its matching <EndFile> element easily, it's a good idea to set up a key to index the <EndFile> elements by their fileName: <xsl:key name="EndFile" match="EndFile" use="@fileName" /> Within a template matching a <BeginFile> element, we can now find the matching <EndFile> element with: key('EndFile', @fileName) We then need to test whether there is a matching <EndFile> element or not; if there isn't, we need an empty element: <xsl:template match="BeginFile"> <xsl:variable name="EndFile" select="key('EndFile', @fileName)" /> <xsl:choose> <xsl:when test="$EndFile"> <File lineNum="{@lineNum}" fileName="{@fileName}"> ... </File> ... </xsl:when> <xsl:otherwise> <File lineNum="{@lineNum}" fileName="{@fileName}" /> ... </xsl:otherwise> </xsl:choose> </xsl:template> In the case where we're creating a <File> element with content, the content comes from processing the following siblings of the <BeginFile> element recursively. The stuff after the <File> element comes from processing whatever comes after the matching <EndFile> element, again recursively: <xsl:template match="BeginFile"> <xsl:variable name="EndFile" select="key('EndFile', @fileName)" /> <xsl:choose> <xsl:when test="$EndFile"> <File lineNum="{@lineNum}" fileName="{@fileName}"> <xsl:apply-templates select="following-sibling::*[1]" /> </File> <xsl:apply-templates select="$EndFile/following-sibling::*[1]" /> </xsl:when> <xsl:otherwise> <File lineNum="{@lineNum}" fileName="{@fileName}" /> ... </xsl:otherwise> </xsl:choose> </xsl:template> When we're creating an empty element, the stuff after the empty <File> element comes from processing the following siblings of the <BeginFile> element recursively: <xsl:template match="BeginFile"> <xsl:variable name="EndFile" select="key('EndFile', @fileName)" /> <xsl:choose> <xsl:when test="$EndFile"> <File lineNum="{@lineNum}" fileName="{@fileName}"> <xsl:apply-templates select="following-sibling::*[1]" /> </File> <xsl:apply-templates select="$EndFile/following-sibling::*[1]" /> </xsl:when> <xsl:otherwise> <File lineNum="{@lineNum}" fileName="{@fileName}" /> <xsl:apply-templates select="following-sibling::*[1]" /> </xsl:otherwise> </xsl:choose> </xsl:template> If you consider the content of a <File> element, most of it is made up of other elements that you just want copied: <xsl:template match="*"> <xsl:copy-of select="." /> ... </xsl:template> But to support the recursion through the siblings, once we've copied that element, we need to go on to its immediately following sibling: <xsl:template match="*"> <xsl:copy-of select="." /> <xsl:apply-templates select="following-sibling::*[1]" /> </xsl:template> Currently the above template will process the <EndFile> elements as well, but we know that as soon as we encounter an <EndFile> element, we've come to the end of the content of the <File> element that we're currently building. So we need a template matching <EndFile> elements that just does nothing: <xsl:template match="EndFile" /> Finally, to kick the whole process off, we have to apply templates to the first element within the <LogFile> element: <xsl:template match="LogFile"> <xsl:apply-templates select="*[1]" /> </xsl:template> And there you have it. If you need any help/explanation, let us know. Cheers, Jeni --- Jeni Tennison http://www.jenitennison.com/ XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
|
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
|