Overcoming unclosed tags in xsl

不想你离开。 提交于 2019-12-14 02:35:55

问题


I'm working on a drop down menu that pulls data from a Sharepoint list and is styled with xsl. The html structure is a simple unordered list

<ul><li>parent page</li><ul><li>sub page 1</li><li>sub page2</li></ul></ul>

The xsl tests if an item in the list is a parent page or a sub page and what the sub page number is. Parent pages have a number so the desired sub pages can be attached to the correct parent page.

The basic xsl for each item is this:

<xsl:for-each select="//Data/Row">
    <xsl:if test="./@Page_x0020_type = 0">
        <li >
            <a>
                <xsl:attribute name="href">
                    <xsl:value-of
                     select="./@Page_x002f_link_x0020_url"/>
                </xsl:attribute>
                <xsl:value-of select="./@Title0"/>
            </a>
        </li>
    </xsl:if>

I want the xsl to equate to this: If it's a sub page, precede the item with a ul tag and if it's the last sub page under a parent, add a closing ul tag.

How do I get around the fact that xsl won't let me add an unclosed ul tag because it (rightly) doesn't know if the tag is going to get closed?

XML

    <Field Type="Text" 
           DisplayName="Page/link url" 
           Required="FALSE" 
           MaxLength="255" 
           Name="Page_x002f_link_x0020_url"/>
    <Field ReadOnly="TRUE" 
           Type="Computed" 
           Name="LinkTitle" 
           DisplayName="Page number"/>
    <Field Type="Text" 
           DisplayName="Title" 
           Required="FALSE" 
           MaxLength="255" 
           Name="Title0"/>  
    <Field Type="Choice" 
           DisplayName="Page type" 
           Required="FALSE" 
           Format="RadioButtons" 
           FillInChoice="FALSE" 
           Name="Page_x0020_type">    
           <CHOICES>  
               <CHOICE>0</CHOICE>  
               <CHOICE>1</CHOICE>  
           </CHOICES>  
           <DefaultFormula>=0</DefaultFormula>  
           <DefaultFormulaValue/>  
    </Field>
    <Field Type="Text" 
           DisplayName="Sub page number" 
           Required="FALSE" 
           MaxLength="2" 
           Name="Sub_x0020_page_x0020_number"/>
    <Field Type="Text" 
           DisplayName="Parent page number" 
           Required="FALSE" 
           MaxLength="1" 
           Name="Parent_x0020_page_x0020_number">
           <Default>0</Default>
    </Field>
</Schema>
<Data ItemCount="1">
    <Row Page_x002f_link_x0020_url="" 
         LinkTitle="" 
         Title0="" 
         Page_x0020_type="" 
         Sub_x0020_page_x0020_number="" 
         Parent_x0020_page_x0020_number="" 
         ul="" 
         _x003c_li_x003e__x003c_a_x003e_="" 
         _x003c__x002f_a_x003e__x003c__x0="" 
         _x003c_ul_x003e__x003c_li_x003e_="" 
         _x003c__x002f_a_x003e__x003c__x00="" 
         _x003c__x002f_a_x003e__x003c__x01=""/>

UPDATE:

Page types:
  • Parent <li>parent1</li>
  • Sub page 1 - needs to start with a <ul>...<li>sub page 1</li>
  • Middle sub pages-(numbered to set sort order-html same as parent page) <li>sub page #</li>
  • Last sub page in group - needs to end with a </ul>

回答1:


I want the xsl to equate to this: If it's a sub page, precede the item with a ul tag and if it's the last sub page under a parent, add a closing ul tag.

You're thinking the wrong way. XSLT doesn't write tags, it writes a tree of nodes. You can't write half a node to the result tree.

In XSLT 2.0 you can probably do what you want using xsl:for-each-group with the group-starting-with attribute - I can't be specific, because you haven't specified the problem clearly enough, but it's probably something like this:

<xsl:template match="parent">
  <xsl:for-each-group select="*" group-starting-with="li[....]">
    <ul>
      <xsl:copy-of select="current-group()"/>
    </ul>
  </xsl:for-each-group>
</xsl:template>

If you're stuck with XSLT 1.0 then it will be more difficult: I would use a technique called "sibling recursion" in which you apply-templates to the first child, which in turn applies templates to the next sibling, and so on. The template rule for the parent does this:

<xsl:template match="parent">
  <xsl:apply-templates select="*[1]"/>
</xsl:template>

The template rule for a sibling that is to be the first in a group does this:

<xsl:template match="parent/*[ (: where this is the first in a group :) ]">
  <group>
    <xsl:copy-of select="."/>
    <xsl:apply-templates select="following-sibling::*[1]"/>
  </group>
  <xsl:apply-templates select="following-sibling::*[(* start of next group *)][1]"/>
</xsl:template>

and the template rule for other siblings does:

<xsl:template match="parent/*">
  <xsl:copy-of select="."/>
  <xsl:apply-templates select="following-sibling::*[1]"/>
</xsl:template>

The details can be tricky even for experienced XSLT developers.




回答2:


I am missing something. As XSL is an XML document that can be used to transform another XML (XHTML, SOAP, etc) document into another format, which is generally XML of some sort. If you feed a data document (string, etc) into a XSL, it transform according to the pattern you have set, which must be valid XML.

Now, why is this a problem in your instance. Are you only building part of the structure and then adding it to another part until you have the whole? If so, I would pull all of the bits into one piece of data (file, string, etc) and run the transformation on it. Or, leave placeholders in the highest level, properly end tagged, and add the child bits in that way.

Looking at your question, I see you want one valid and one invalid , which leads me to believe you are trying to piecemeal a solution. Unfortunately, I know of no way to tell XSL "hey this is invalid XML, but don't sweat it".



来源:https://stackoverflow.com/questions/5823938/overcoming-unclosed-tags-in-xsl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!