代码之家  ›  专栏  ›  技术社区  ›  David Basarab

不同元素和分组

  •  8
  • David Basarab  · 技术社区  · 16 年前

    给定以下XML片段:

    <Problems>
      <Problem>
        <File>file1</File>
        <Description>desc1</Description>
      </Problem>
      <Problem>
        <File>file1</File>
        <Description>desc2</Description>
      </Problem>
      <Problem>
        <File>file2</File>
        <Description>desc1</Description>
      </Problem>
    </Problems>
    

    我需要做一些

    <html>
      <body>
        <h1>file1</h1>
        <p>des1</p>
        <p>desc2</p>
        <h1>file2</h1>
        <p>des1</p>
      </body>
    </html>
    

    我试过用钥匙,比如

    <xsl:key name="files" match="Problem" use="File"/>
    

    但我真的不知道该如何进入下一步,或者这是否是正确的方法。

    3 回复  |  直到 11 年前
        1
  •  5
  •   Richard A    16 年前

    以下是我将如何使用muenchean方法。谷歌“Xslt Muenchean”可以从更聪明的人那里获得更多信息。也许有一个聪明的方法,但我会把它留给别人。

    注意,我避免在XML元素名称的开头使用大写字母,例如“file”,但这取决于您自己。

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="html"/>
        <xsl:key name="files" match="/Problems/Problem/File" use="./text()"/>
        <xsl:template match="/">
            <html>
                <body>
                    <xsl:apply-templates select="Problems"/>
                </body>
            </html>
        </xsl:template>
        <xsl:template match="Problems">
            <xsl:for-each select="Problem/File[generate-id(.) = generate-id(key('files', .))]">
                <xsl:sort select="."/>
                <h1>
                    <xsl:value-of select="."/>
                </h1>
                <xsl:apply-templates select="../../Problem[File=current()/text()]"/>
            </xsl:for-each>
        </xsl:template>
        <xsl:template match="Problem">
            <p>
                <xsl:value-of select="Description/text()"/>
            </p>
        </xsl:template>
    </xsl:stylesheet>
    

    其思想是,使用文本值为每个文件元素设置关键点。然后,仅当文件值与键控元素相同时才显示文件值。要检查它们是否相同,请使用generate-id。在比较匹配的第一个元素时,有一种类似的方法。我不能告诉你哪个效率更高。

    我已经使用我最喜欢的XSLT工具marrowsoft xselerator测试了这里的代码,尽管它已经不可用了,afaik。我得到的结果是:

    <html>
    <body>
    <h1>file1</h1>
    <p>desc1</p>
    <p>desc2</p>
    <h1>file2</h1>
    <p>desc1</p>
    </body>
    </html>
    

    这是使用msxml4。

    我已按文件对输出进行了排序。我不确定你是否想要。

    我希望这有帮助。

        2
  •  7
  •   Dimitre Novatchev    16 年前

    这个解决方案有点简单,效率更高,同时也更一般 比理查德提出的:

    这种转变 :

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!--                                            -->
     <xsl:key name="kFileByVal" match="File"
           use="." />
    <!--                                            -->
     <xsl:key name="kDescByFile" match="Description"
           use="../File"/>
    <!--                                            -->
        <xsl:template match="/*">
         <html>
          <body>
          <xsl:for-each select=
             "*/File[generate-id()
                    =
                     generate-id(key('kFileByVal',.)[1])]">
            <h1><xsl:value-of select="."/></h1>
            <xsl:for-each select="key('kDescByFile', .)">
              <p><xsl:value-of select="."/></p>
            </xsl:for-each>
          </xsl:for-each>
          </body>
         </html>
        </xsl:template>
    </xsl:stylesheet>
    

    当应用于提供的XML文档时 :

    <Problems>
        <Problem>
            <File>file1</File>
            <Description>desc1</Description>
        </Problem>
        <Problem>
            <File>file1</File>
            <Description>desc2</Description>
        </Problem>
        <Problem>
            <File>file2</File>
            <Description>desc1</Description>
        </Problem>
    </Problems>
    

    产生想要的结果 :

    <html>
       <body>
          <h1>file1</h1>
          <p>desc1</p>
          <p>desc2</p>
          <h1>file2</h1>
          <p>desc1</p>
       </body>
    </html>
    

    做笔记 第一个的简单匹配模式 <xsl:key> 如何,用一秒钟 <XSL:Key & GT; 我们找到了所有 Description “作为a的兄弟元素” File “具有给定值的元素。

    我们可以用更多的模板来代替 <xsl:for-each> 然而,拉处理是一个非常简单的情况,解决方案真正受益于更短、更紧凑和更可读的代码。

    还要注意,在 XSLT 2.0 通常会使用 <xsl:for-each-group> 指令 而不是 Muenchian method .

        3
  •  0
  •   Nick Grealy    11 年前

    这个 XSLT 1 解决方案也会起作用。比其他解决方案更简洁一点!

      <xsl:template match="/">           
        <html><body>
          <xsl:for-each select="//File[not(.=preceding::*)]">
            <h1><xsl:value-of select="." /></h1>
            <xsl:for-each select="//Problem[File=current()]/Description">
              <p><xsl:value-of select="." /></p>
            </xsl:for-each>
          </xsl:for-each>
        </body></html>
      </xsl:template>
    

    结果:

    <html xmlns="http://www.w3.org/1999/xhtml">
      <body>
        <h1>file1</h1>
        <p>desc1</p>
        <p>desc2</p>
        <h1>file2</h1>
        <p>desc1</p>
      </body>
    </html>