Subject: [xsl] Nested sections from flat structure From: Linda van den Brink <lvdbrink@xxxxxxx> Date: Thu, 10 May 2001 15:33:36 +0200 |
Hi all, I'm wondering about the best (shortest or most elegant or easiest) way to transform an XML document with a 'flat' structure (like an HTML document segmented with h* elements) to an XML document with nested sections. I've been looking at ways to do this (XSL FAQ, Jeni's pages) and have succeeded in doing it myself. But now I'm wondering if there are better ways than what I've come up with. My source documents are a bit troublesome. They have a structure like HTML. There are two elements that indicate start of a section, <head> and <a name="">. Both appear inside a p element. A source document can be: - without subsections - with subsections indicated by <head> - with subsections indicated by <a name=""> - with subsections indicated by <a name="">, and <head> subsections inside the first subsections - with subsections indicated by <head>, and <a name=""> subsections inside the first subsections My solution is below. It's based on for-each. I'm hoping there's a better way to do this, because this stylesheet is quite long and difficult to read/understand for others. Is there a solution that *pushes* the elements from the flat structure into sections, instead of pulling like mine does? SOURCE XML (remember this is one of 5 variants) <?xml version="1.0" encoding="iso-8859-1"?> <topic> <text> <p>first some intro text</p> <p><head>A</head> goes with A.</p> <p><a name="A.1"/></p> <p>Text with A.1</p> <p>More text with A.1</p> <p><a name="A.2"/></p> <p>text with A.2</p> <p>Goes with A.2</p> <p><head>B</head> Goes with B.</p> <p>Goes with B.</p> <p><head>C</head> Goes with C</p> <p>Goes with C</p> </text> </topic> STYLESHEET <?xml version="1.0" encoding="iso-8859-1"?> Hi all, I'm wondering about the best (shortest or most elegant or easiest) way to transform an XML document with a 'flat' structure (like an HTML document segmented with h* elements) to an XML document with nested sections. I've been looking at ways to do this (XSL FAQ, Jeni's pages) and have succeeded in doing it myself. But now I'm wondering if there are better ways than what I've come up with. My source documents are a bit troublesome. They have a structure like HTML. There are two elements that indicate start of a section, <head> and <a name="">. Both appear inside a p element. A source document can be: - without subsections - with subsections indicated by <head> - with subsections indicated by <a name=""> - with subsections indicated by <a name="">, and <head> subsections inside the first subsections - with subsections indicated by <head>, and <a name=""> subsections inside the first subsections So, here's my solution. It's based on for-each. I'm hoping there's a better way to do this, because this stylesheet is quite long and difficult to read/understand for others. Is there a solution that *pushes* the elements from the flat structure into sections, instead of pulling like mine does? SOURCE XML (remember this is one of 5 variants) <?xml version="1.0" encoding="iso-8859-1"?> <topic> <text> <p>first some intro text</p> <p><head>A</head> goes with A.</p> <p><a name="A.1"/></p> <p>Text with A.1</p> <p>More text with A.1</p> <p><a name="A.2"/></p> <p>text with A.2</p> <p>Goes with A.2</p> <p><head>B</head> Goes with B.</p> <p>Goes with B.</p> <p><head>C</head> Goes with C</p> <p>Goes with C</p> </text> </topic> STYLESHEET <?xml version="1.0" encoding="is<?xml version="1.0" encoding="iso-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="text"> <GeneralSection> <xsl:choose> <xsl:when test="p[a[@name]][not(preceding-sibling::p[head])]"> <xsl:for-each select="p[not(preceding-sibling::p/a[@name])][not(a[@name])]"> <xsl:call-template name="blockcontent"/> </xsl:for-each> <xsl:for-each select="p[a[@name]]"> <xsl:variable name="id" select="generate-id()"/> <GeneralSection ID="{a/@name}"> <xsl:choose> <xsl:when test="following-sibling::p[head]"> <xsl:for-each select="following-sibling::p[not(preceding-sibling::p[head])][not(self::p[he ad])]"> <xsl:call-template name="blockcontent"/> </xsl:for-each> <xsl:for-each select="following-sibling::p[head]"> <xsl:variable name="headid" select="generate-id()"/> <GeneralSection> <SectionTitle><xsl:value-of select="head"/></SectionTitle> <Paragraph><xsl:apply-templates select="node()[not(self::head)]"/></Paragraph> <xsl:for-each select="following-sibling::p[generate-id(preceding-sibling::p[head][1])=$hea did][not(head)] [generate-id(preceding-sibling::p[a[@name]][1])=$id][not(a[@name])]"> <xsl:call-template name="blockcontent"/> </xsl:for-each> </GeneralSection> </xsl:for-each> </xsl:when> <xsl:otherwise> <xsl:for-each select="following-sibling::p[generate-id(preceding-sibling::p[a[@name]][1])= $id][not(a[@name])]"> <xsl:call-template name="blockcontent"/> </xsl:for-each> </xsl:otherwise> </xsl:choose> </GeneralSection> </xsl:for-each> </xsl:when> <xsl:when test="p[head][not(preceding-sibling::p[a[@name]])]"> <xsl:for-each select="p[not(preceding-sibling::p[head])][not(head)]"> <xsl:call-template name="blockcontent"/> </xsl:for-each> <xsl:for-each select="p[head]"> <xsl:variable name="id" select="generate-id()"/> <GeneralSection> <SectionTitle><xsl:value-of select="head"/></SectionTitle> <Paragraph><xsl:apply-templates select="node()[not(self::head)]"/></Paragraph> <xsl:choose> <xsl:when test="following-sibling::p[a[@name]]"> <xsl:for-each select="following-sibling::p[a[@name]]"> <xsl:variable name="headid" select="generate-id()"/> <GeneralSection ID="{a/@name}"> <xsl:for-each select="following-sibling::p[generate-id(preceding-sibling::p[a[@name]][1])= $headid][not(a)] [generate-id(preceding-sibling::p[head][1])=$id][not(head)]"> <xsl:call-template name="blockcontent"/> </xsl:for-each> </GeneralSection> </xsl:for-each> </xsl:when> <xsl:otherwise> <xsl:for-each select="following-sibling::p[generate-id(preceding-sibling::p[head][1])=$id] [not(head)]"> <xsl:call-template name="blockcontent"/> </xsl:for-each> </xsl:otherwise> </xsl:choose> </GeneralSection> </xsl:for-each> </xsl:when> <xsl:otherwise> <xsl:call-template name="blockcontent"/> </xsl:otherwise> </xsl:choose> </GeneralSection> </xsl:template> <xsl:template name="blockcontent"> <xsl:for-each select="descendant-or-self::p"> <Paragraph><xsl:apply-templates/></Paragraph> </xsl:for-each> </xsl:template> </xsl:stylesheet> OUTPUT XML <?xml version="1.0" encoding="utf-8"?> <GeneralSection> <Paragraph>first some intro text</Paragraph> <GeneralSection> <SectionTitle>A</SectionTitle> <Paragraph>goes with A.</Paragraph> <GeneralSection ID="A.1"> <Paragraph>Text with A.1</Paragraph> <Paragraph>More text with A.1</Paragraph> </GeneralSection> <GeneralSection ID="A.2"> <Paragraph>text with A.2</Paragraph> <Paragraph>Goes with A.2</Paragraph> </GeneralSection> </GeneralSection> <GeneralSection> <SectionTitle>B</SectionTitle> <Paragraph>Goes with B.</Paragraph> <Paragraph>Goes with B.</Paragraph> </GeneralSection> <GeneralSection> <SectionTitle>C</SectionTitle> <Paragraph>Goes with C</Paragraph> <Paragraph>Goes with C</Paragraph> </GeneralSection> </GeneralSection> Suggestions? Linda OUTPUT XML <?xml version="1.0" encoding="utf-8"?> <GeneralSection> <Paragraph>first some intro text</Paragraph> <GeneralSection> <SectionTitle>A</SectionTitle> <Paragraph>goes with A.</Paragraph> <GeneralSection ID="A.1"> <Paragraph>Text with A.1</Paragraph> <Paragraph>More text with A.1</Paragraph> </GeneralSection> <GeneralSection ID="A.2"> <Paragraph>text with A.2</Paragraph> <Paragraph>Goes with A.2</Paragraph> </GeneralSection> </GeneralSection> <GeneralSection> <SectionTitle>B</SectionTitle> <Paragraph>Goes with B.</Paragraph> <Paragraph>Goes with B.</Paragraph> </GeneralSection> <GeneralSection> <SectionTitle>C</SectionTitle> <Paragraph>Goes with C</Paragraph> <Paragraph>Goes with C</Paragraph> </GeneralSection> </GeneralSection> Suggestions? Linda XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
RE: [xsl] xmlspy and copy-of, Michael Kay | Thread | Re: [xsl] Nested sections from flat, Jeni Tennison |
Re: [xsl] creating a toc with links, Patricia Quintin | Date | RE: [xsl] creating a toc with links, Chris Bayes |
Month |