Subject: Re: [xsl] Deepening a flat structure and numbering nodes From: Emmanuel Bégué <medusis@xxxxxxxxx> Date: Sat, 10 Aug 2013 18:19:07 +0200 |
Grouping in XSLT 1.0 is best done with keys; this key: <xsl:key name="records" match="*[not(self::Category)]" use="generate-id(preceding-sibling::Category[1])"/> sets a key for any element that is not a <Category> as the id of the preceding Category element. Then the grouping can be done according to that key, and so can be the counting within a "group". Here's the full stylesheet: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl"> <xsl:output method="xml" indent="yes" encoding="UTF-8"/> <xsl:key name="records" match="*[not(self::Category)]" use="generate-id(preceding-sibling::Category[1])"/> <xsl:template match="/*"> <data> <xsl:apply-templates select="Story/Category"/> </data> </xsl:template> <xsl:template match="Category"> <xsl:variable name="key" select="generate-id(.)"/> <newRecord> <Category> <xsl:value-of select="substring-before(., ':')"/> </Category> <Subcategory> <xsl:value-of select="normalize-space(substring-after(., ':'))"/> </Subcategory> <Case> <xsl:number/> </Case> <xsl:apply-templates select="key('records', $key)"> <xsl:with-param name="key" select="$key"/> </xsl:apply-templates> </newRecord> </xsl:template> <xsl:template match="*"> <xsl:copy-of select="."/> </xsl:template> <xsl:template match="DifferentialDiagnosis"> <xsl:param name="key"/> <xsl:element name="{concat(name(), count(preceding-sibling::DifferentialDiagnosis[generate-id(preceding-sibling::Category[1]) = $key]) + 1)}"> <xsl:apply-templates/> </xsl:element> </xsl:template> </xsl:stylesheet> This produces the following result: <data> <newRecord> <Category>Category</Category> <Subcategory>Subcategory</Subcategory> <Case>1</Case> <CaseTitle>Title One</CaseTitle> <Institution>Institution One</Institution> <Author>Authors One</Author> <History>History One</History> <DifferentialDiagnosis1>Sick</DifferentialDiagnosis1> <DifferentialDiagnosis2>Sicker</DifferentialDiagnosis2> <DifferentialDiagnosis3>Sickest</DifferentialDiagnosis3> <TeachingPoint>Point1</TeachingPoint> <TeachingPoint>Point2</TeachingPoint> </newRecord> <newRecord> <Category>Category One</Category> <Subcategory>Subcategory</Subcategory> <Case>2</Case> <CaseTitle>Title Two</CaseTitle> <Institution>Title Two</Institution> <Author>Author Two</Author> <History>History Two</History> <DifferentialDiagnosis1>Sick</DifferentialDiagnosis1> <DifferentialDiagnosis2>Sicker</DifferentialDiagnosis2> <DifferentialDiagnosis3>Sickest</DifferentialDiagnosis3> <TeachingPoint>Point1</TeachingPoint> <TeachingPoint>Point2</TeachingPoint> </newRecord> </data> Hope this helps. Regards, EB On Sat, Aug 10, 2013 at 2:53 PM, Rick Quatro <rick@xxxxxxxxxxxxxx> wrote: > Hi All, > > Here is my input XML: > > <?xml version="1.0" encoding="UTF-8"?> > <Cases> > <Story> > <Category>Category: Subcategory</Category> > <CaseTitle>Title One</CaseTitle> > <Institution>Institution One</Institution > > <Author>Authors One</Author> > <History>History One</History> > <DifferentialDiagnosis>Sick</DifferentialDiagnosis> > <DifferentialDiagnosis>Sicker</DifferentialDiagnosis> > <DifferentialDiagnosis>Sickest</DifferentialDiagnosis> > <TeachingPoint>Point1</TeachingPoint> > <TeachingPoint>Point2</TeachingPoint> > <Category>Category One: Subcategory</Category> > <CaseTitle>Title Two</CaseTitle> > <Institution>Title Two</Institution > > <Author>Author Two</Author> > <History>History Two</History> > <DifferentialDiagnosis>Sick</DifferentialDiagnosis> > <DifferentialDiagnosis>Sicker</DifferentialDiagnosis> > <DifferentialDiagnosis>Sickest</DifferentialDiagnosis> > <TeachingPoint>Point1</TeachingPoint> > <TeachingPoint>Point2</TeachingPoint> > </Story> > </Cases> > > I want to organize the data in a deeper structure like this: > > <?xml version="1.0" encoding="UTF-8"?> > <data> > <newRecord> > <Category>Category</Category> > <Subcategory>Subcategory</Subcategory> > <Case>1</Case> > <CaseTitle>Title One</CaseTitle> > <Institution>Institution One</Institution> > <Author>Authors One</Author> > <History>History One</History> > <DifferentialDiagnosis>Sick</DifferentialDiagnosis> > <DifferentialDiagnosis>Sicker</DifferentialDiagnosis> > <DifferentialDiagnosis>Sickest</DifferentialDiagnosis> > <TeachingPoint>Point1</TeachingPoint> > <TeachingPoint>Point2</TeachingPoint> > </newRecord> > <newRecord> > <Category>Category One</Category> > <Subcategory>Subcategory</Subcategory> > <Case>2</Case> > <CaseTitle>Title Two</CaseTitle> > <Institution>Title Two</Institution> > <Author>Author Two</Author> > <History>History Two</History> > <DifferentialDiagnosis>Sick</DifferentialDiagnosis> > <DifferentialDiagnosis>Sicker</DifferentialDiagnosis> > <DifferentialDiagnosis>Sickest</DifferentialDiagnosis> > <TeachingPoint>Point1</TeachingPoint> > <TeachingPoint>Point2</TeachingPoint> > </newRecord> > </data> > > With help from the list, I am using this to get the results. > > <?xml version="1.0" encoding="UTF-8"?> > <xsl:stylesheet version="1.0" > xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> > > <xsl:output indent="yes" /> > > <xsl:template match="Cases/Story"> > <data> > <xsl:apply-templates select="Category[1]" /> > </data> > </xsl:template> > > <xsl:template match="Category"> > <xsl:element name="newRecord"> > <Category><xsl:value-of select="substring-before(.,': > ')"/></Category> > <Subcategory><xsl:value-of select="substring-after(.,': > ')"/></Subcategory> > <Case><xsl:number count="Category"/></Case> > <xsl:apply-templates > select="following-sibling::*[1][not(self::Category)]" > mode="in-case-siblings"/> > </xsl:element> > <xsl:apply-templates select="following-sibling::Category[1]"/> > </xsl:template> > > <xsl:template match="*" mode="in-case-siblings"> > <xsl:copy-of select="." /> > <xsl:apply-templates > select="following-sibling::*[1][not(self::Category)]" > mode="in-case-siblings"/> > </xsl:template> > > <xsl:template match="Category" mode="in-case-siblings"/> > > </xsl:stylesheet> > > This is working well, but now I need to do something different to the > <DifferentialDiagnosis> elements. I want to change the element names by > numbering them sequentially within my <newRecord> element, like this: > > <?xml version="1.0" encoding="UTF-8"?> > <data> > <newRecord> > <Category>Category</Category> > <Subcategory>Subcategory</Subcategory> > <Case>1</Case> > <CaseTitle>Title One</CaseTitle> > <Institution>Institution One</Institution> > <Author>Authors One</Author> > <History>History One</History> > <DifferentialDiagnosis1>Sick</DifferentialDiagnosis1> > <DifferentialDiagnosis2>Sicker</DifferentialDiagnosis2> > <DifferentialDiagnosis3>Sickest</DifferentialDiagnosis3> > <TeachingPoint>Point1</TeachingPoint> > <TeachingPoint>Point2</TeachingPoint> > </newRecord> > <newRecord> > <Category>Category One</Category> > <Subcategory>Subcategory</Subcategory> > <Case>2</Case> > <CaseTitle>Title Two</CaseTitle> > <Institution>Title Two</Institution> > <Author>Author Two</Author> > <History>History Two</History> > <DifferentialDiagnosis1>Sick</DifferentialDiagnosis1> > <DifferentialDiagnosis2>Sicker</DifferentialDiagnosis2> > <DifferentialDiagnosis3>Sickest</DifferentialDiagnosis3> > <TeachingPoint>Point1</TeachingPoint> > <TeachingPoint>Point2</TeachingPoint> > </newRecord> > </data> > > I added this rule to my stylesheet: > > <xsl:template match="DifferentialDiagnosis" mode="in-case-siblings"> > <xsl:variable name="diagnosis"><xsl:number > count="DifferentialDiagnosis" from="Category"/></xsl:variable> > <xsl:element name="{concat(name(),$diagnosis)}"><xsl:value-of > select="."/></xsl:element> > <xsl:apply-templates > select="following-sibling::*[1][not(self::Category)]" > mode="in-case-siblings"/> > </xsl:template> > > This basically "works" except the numbers are sequential throughout the > document. > > <data> > <newRecord> > ... > <DifferentialDiagnosis1>Sick</DifferentialDiagnosis1> > <DifferentialDiagnosis2>Sicker</DifferentialDiagnosis2> > <DifferentialDiagnosis3>Sickest</DifferentialDiagnosis3> > ... > </newRecord> > <newRecord> > ... > <DifferentialDiagnosis1>Sick</DifferentialDiagnosis5> > <DifferentialDiagnosis2>Sicker</DifferentialDiagnosis6> > <DifferentialDiagnosis3>Sickest</DifferentialDiagnosis7> > ... > </newRecord> > </data> > > I need the numbers to reset for each <newRecord> element. I am sorry for the > long post, but I want to be complete as possible. Also, for this project, I > need to use XSLT 1.0. Thank you very much. > > Rick
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] Deepening a flat structur, G. Ken Holman | Thread | Re: [xsl] Deepening a flat structur, Kevin Brown |
Re: [xsl] Deepening a flat structur, G. Ken Holman | Date | [xsl] Grouping within a group, Rick Quatro |
Month |