如何使用XSL在XML转换中查找随机元素

时间:2019-07-12 07:26:18

标签: xml xslt xhtml transform

我在转换XML时遇到问题,就像我无法按正确的顺序获取元素。这些元素是随机的,无法预测它们的顺序。

这是我的XML

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<toc>
    <layout>
        <header>Item 1</header>
        <tocItem>item one - a</tocItem>
        <tocItem>item one - b</tocItem>
        <header>Item 2</header>
        <tocItem>item two - a</tocItem>
        <tocItem>item two - b</tocItem>
        <tocItem>item two - c</tocItem>
        <tocItem>item two - d</tocItem>
        <tocItem>item two - e</tocItem>
        <header>Item 3</header>
        <tocItem>item three - a</tocItem>
        <header>Item 4</header>
        <tocItem>item four - a</tocItem>
        <tocItem>item four - b</tocItem>
        <tocItem>item four - c</tocItem>
        <header>Item 5</header>
        <tocItem>item five - a</tocItem>
        <tocItem>item five - b</tocItem>
    </layout>
    <layout>
        <header>Item 1</header>
        <tocItem>item one - a</tocItem>
        <tocItem>item one - b</tocItem>
        <header>Item 2</header>
        <tocItem>item two - a</tocItem>  
    </layout>
    <layout>
        <header>Item 1</header>
        <tocItem>item one - a</tocItem>
        <tocItem>item one - b</tocItem>
        <tocItem>item one - c</tocItem>
        <tocItem>item one - d</tocItem>
        <tocItem>item one - e</tocItem>
        <header>Item 2</header>
        <tocItem>item two - c</tocItem>
        <tocItem>item two - d</tocItem>
        <tocItem>item two - e</tocItem>
        <header>Item 4</header>
        <tocItem>item four - a</tocItem>
        <tocItem>item four - b</tocItem>
        <header>Item 5</header>
        <tocItem>item five - a</tocItem>  
    </layout>
</toc>

这里是XSL

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:template match="/">

            <html lang="en">
            <head>
                <meta charset="UTF-8" />
                <title>Title</title>
            </head>

            <body>
                <div class="toc">
                    <xsl:for-each select="/toc/layout">
                    <div class="layout">                    
                        <xsl:for-each select="/toc/layout/header">
                            <div class="header">
                                <p><xsl:value-of select="header" /></p>
                            </div>
                        </xsl:for-each>
                        <xsl:for-each select="/toc/layout/tocItem">
                            <div class="tocItem">
                                <p><xsl:value-of select="tocItem" /></p>
                            </div>
                        </xsl:for-each>                    
                    </div>  
                    </xsl:for-each>              
                </div>
            </body>

            </html>
    </xsl:template>
 </xsl:stylesheet>

当我尝试上述方法时,它只是重复第一个标头元素和第一个tocItems。在布局div中尝试此代码<xsl:value-of select="." />时,我得到了所有元素。我的目标是一张一张地取走它们。如下所示。

项目1

第一个-一个

第一项-b

项目2

第二项-

第二项-b

第二项-c

2 个答案:

答案 0 :(得分:1)

我没有检查您要达到的目标,但是您的xsl:for-each显然是错误的。当您编写<xsl:for-each select="/toc/layout">时,for-each中的context节点是一个<layout>元素,人们可能希望进一步选择相对于该元素,而不是从文档根目录开始的绝对路径。我不明白为什么您一开始会有两个xsl:for-each级别。

答案 1 :(得分:1)

通常,如果您只想根据元素名称使用div属性将所有这些元素转换为HTML class,则只需一个模板即可:

  <xsl:template match="toc | layout | header | tocItem">
      <div class="{local-name()}">
          <xsl:apply-templates/>
      </div>
  </xsl:template>

要保持输入顺序,最好简单地apply-templates或至少最简单。

一个例子是

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:output method="html" indent="no" html-version="5"/>

  <xsl:template match="/">
    <html>
      <head>
        <title>.NET XSLT Fiddle Example</title>
      </head>
      <body>
        <xsl:apply-templates/>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="toc | layout | header | tocItem">
      <div class="{local-name()}">
          <xsl:apply-templates/>
      </div>
  </xsl:template>

</xsl:stylesheet>

使用仅XSLT 3声明<xsl:mode on-no-match="shallow-copy"/>将身份转换设置为默认处理,但是在早期版本中,您只需将其拼写为

<xsl:template match="@* | node()">
  <xsl:copy>
     <xsl:apply-templates select="@* | node()"/>
  </xsl:copy>
</xsl:template>

请参见https://xsltfiddle.liberty-development.net/ncdD7ne在线进行实验。