2017-02-10 95 views
0

我一直在编辑,看着这么久,我没有找到一个看似简单的解决方案。处理动态创建的孩子和兄弟姐妹的子女

一个元素(及其兄弟)将有任意数量的不同(动态)结果,我希望在HTML表格中显示每个cd文件对的一行。最初我认为我可以避免每个循环(似乎无论如何都会返回相同的结果),但我需要一种[更好的]方式来引用孩子。下面的来源与我工作的结构类似。

例如,某些“cd”和“文件”将包含更多元素,例如价格,有些可能没有信息。

XML

<?xml version="1.0" encoding="UTF-8"?> 
    <?xml-stylesheet type="text/xsl" href="cdcatalog.test2.xsl"?> 
    <catalog> 
     <rock> 
     <album> 
      <cd> 
      <title>Empire Burlesque</title> 
      <artist>Bob Dylan</artist> 
      </cd> 
      <file> 
      <store>Apple</store> 
      <size>3823</size> 
      </file> 
     </album> 
     <album> 
      <cd> 
      <title>Hide your heart</title> 
      <artist>Bonnie Tyler</artist> 
      </cd> 
      <file> 
      <store>Amazon</store> 
      <size>2123</size> 
      </file> 
     </album> 
     </rock> 
    </catalog> 

XSLT

<?xml version="1.0" encoding="UTF-8"?> 
    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="/"> 
    <html> 
    <body> 
     <h2>My CD Collection</h2> 
     <table border="1"> 
     <tr bgcolor="#cccccc"> 
      <th style="text-align:left">Title</th> 
      <th style="text-align:left">Artist</th> 
      <th style="text-align:left">Store</th> 
      <th style="text-align:left">Size</th> 
     </tr> 
     <xsl:apply-templates/> 
     </table> 
    </body> 
    </html> 
    </xsl:template> 

    <xsl:template match="album"> 
     <tr> 
     <xsl:apply-templates select="cd"/> 
     <xsl:apply-templates select="file"/> 
     </tr> 
    </xsl:template> 

    <xsl:template match="cd"> 
     <td> 
     <xsl:value-of select="."/> 
     </td> 
    </xsl:template> 

    <xsl:template match="file"> 
     <td> 
     <xsl:value-of select="."/> 
     </td> 
    </xsl:template> 

    </xsl:stylesheet> 

结果

<table border="1"> 
     <tbody> 
     <tr bgcolor="#cccccc"> 
      <th style="text-align:left">Title</th> 
      <th style="text-align:left">Artist</th> 
      <th style="text-align:left">Store</th> 
      <th style="text-align:left">Size</th> 
     </tr> 
     <tr> 
      <td> 
      Empire Burlesque 
      Bob Dylan 
      </td> 
      <td> 
       Apple 
       3823 
      </td> 
     </tr> 
     <tr> 
      <td> 
      Hide your heart 
      Bonnie Tyler 
      </td> 
      <td> 
      Amazon 
      2123 
      </td> 
     </tr> 
     </tbody> 
    </table> 

Result View

现在,我想我看到发生了什么。根据我的理解,在XSLT文件的“cd”和“文件”模板下,select="."正在返回<td>内的所有子项。我需要一种方法让每个人都有一个<td>。我已经为“cd”和“file”模板中的每个“cd”和“file”以及for-each尝试了诸如call-template之类的东西。请注意,我还需要动态构建<th>元素,现在它们是为测试目的而手动创建的。有什么建议么?

+0

我们需要一个更好的“动态”定义。例如,你可以说你想为每个叶节点添加一个文本值的列。但是,我没有看到一种方法可以避免硬编码哪些元素会产生一行。 –

+0

我指的是动态而不是静态。 [列数]列将被动态创建,具体取决于API调用返回的内容。将会有0个或更多子元素,在这种情况下,叶子可能包含也可能不包含任何文本,并且可能具有不同的节点名称(顺序不同)(每个节点名称中应包含一列)。 – MasterWill

+0

这是不够的,说什么会改变。您需要告诉我们什么不会 - 以便我们可以使用它来创建输出表的结构。如果没有限制,那么这个任务是不可能的。 –

回答

1

作为一个有教养的猜测(它不完全清楚你的预期输出是什么样子,输入文件的哪些方面是可变的),我想你需要以下内容。

没有必要以一般的方式明确地将模板应用到cdtitle元素,只是apply-templates。此外,您的样式表当前缺少storesize等的模板。据我所知,这些元素的内容应该在HTML输出中的td元素内,所以你需要将它们与模板匹配,即使这些模板相当一般。

如果你不知道表头th事先的名字,如果有那是album孙子叶元素的变量数,这里是一个更“动态”的解决方案:

XSLT样式表

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" 
     encoding="UTF-8" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="/"> 
     <html> 
      <body> 
       <h2>My CD Collection</h2> 
       <table border="1"> 
        <tr bgcolor="#cccccc"> 
         <xsl:for-each select="distinct-values(catalog/rock/album/*/*/name())"> 
          <th style="text-align:left"> 
           <xsl:value-of select="."/> 
          </th> 
         </xsl:for-each> 
        </tr> 
        <xsl:apply-templates/> 
       </table> 
      </body> 
     </html> 
    </xsl:template> 

    <xsl:template match="album"> 
     <tr> 
      <xsl:apply-templates/> 
     </tr> 
    </xsl:template> 

    <xsl:template match="album/*/*"> 
     <td> 
      <xsl:value-of select="."/> 
     </td> 
    </xsl:template> 

</xsl:stylesheet> 

HTML输出

<!DOCTYPE html 
    PUBLIC "XSLT-compat"> 
<html> 
    <body> 
     <h2>My CD Collection</h2> 
     <table border="1"> 
     <tr bgcolor="#cccccc"> 
      <th style="text-align:left">title</th> 
      <th style="text-align:left">artist</th> 
      <th style="text-align:left">store</th> 
      <th style="text-align:left">size</th> 
     </tr> 
     <tr> 
      <td>Empire Burlesque</td> 
      <td>Bob Dylan</td> 
      <td>Apple</td> 
      <td>3823</td> 
     </tr> 
     <tr> 
      <td>Hide your heart</td> 
      <td>Bonnie Tyler</td> 
      <td>Amazon</td> 
      <td>2123</td> 
     </tr> 
     </table> 
    </body> 
</html> 

渲染HTML

enter image description here

在线here尝试这种解决方案。

+0

感谢您的解决方案和快速响应。我不想以“我是XSLT新手”开始我的问题,但这是我的第一个尝试解决方案后,我才意识到现代Web浏览器仍然使用XSLT 1.0!即便如此,我仍然确信这是最好的答案,幸运的是我的应用程序使用XSLT 2.0。 [link](http://xsltransform.net)的链接也很有用,我不知道这样的网站。再次感谢! – MasterWill

1

如果我猜正确,你想要做的事,如:与每一个叶节点

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:strip-space elements="*"/> 

<xsl:template match="/catalog"> 
    <html> 
     <body> 
      <h2>My CD Collection</h2> 
      <table border="1"> 
       <tr> 
        <xsl:apply-templates select="*/album[1]" mode="header"/> 
       </tr> 
       <xsl:apply-templates/> 
      </table> 
     </body> 
    </html> 
</xsl:template> 

<xsl:template match="album"> 
    <tr> 
     <xsl:apply-templates/> 
    </tr> 
</xsl:template> 

<xsl:template match="*[text()]" mode="header"> 
    <th> 
     <xsl:value-of select="name()"/> 
    </th> 
</xsl:template> 

<xsl:template match="*[text()]"> 
    <td> 
     <xsl:value-of select="."/> 
    </td> 
</xsl:template> 

</xsl:stylesheet> 

这对每个album创建行和列文本节点。

请注意,这假定您的输入是常规的 -​​ 即每个专辑具有相同的属性,顺序相同,并且它们都不是空的。

+0

我没有测试过这个,但它看起来像XSLT 1.0的一个好开始。问题是,在我的情况下,专辑可能有不同的属性,按随机顺序排列,可能会有空的结果。 – MasterWill

+0

那么这个和接受的答案都不适合你。 –

+0

如何?接受的答案适合我的问题,并给了我进一步的见解,因为我是新来的这个非常令人沮丧但潜在非常有用的技术:) – MasterWill