如何用XSLT将特定类的未知XML元素格式化为HTML?

问题描述:

所以,我有我的应用程序是这样生成的XML文档:如何用XSLT将特定类的未知XML元素格式化为HTML?

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE AddressBook> 
<?xml-stylesheet type="text/xsl" href="stylesheet.xsl"?> 
<AddressBook> 
<Item> 
    <UserGeneratedElementName1 class="info">Whatever blah blah</UserGeneratedElementName1> 
    <UserGeneratedElementName2 class="info">Whatever blah blah</UserGeneratedElementName2> 
</Item> 
<Item> 
    <UserGeneratedElementName3 class="info">Whatever blah blah</UserGeneratedElementName3> 
</Item> 
... 
... 
Other Items with user-generated elements with user-generated content... 
</AddressBook> 

而且我希望把它变成一个类似的HTML文档:

<html> 
<head> 
<title>AddressBook</title> 
</head> 
<body> 
<div class="root"> 
    <div class="item"> 
    <b>UserGeneratedElementName1:</b> Whatever blah blah 
    <b>UserGeneratedElementName2:</b> Whatever blah blah 
    </div> 
    <div class="item"> 
    <b>UserGeneratedElementName3:</b> Whatever blah blah 
    </div> 
    ... 
    ... 
    Other transformed items... 
</div> 
</body> 
</html> 

我试图让一抓的XSLT语法,但是所有的指南要么太模糊,不能帮助我解决这个问题,要么太深入。另外XSLT语法看起来很混乱。 在此先感谢。

+0

“所有的指南都太模糊,无法帮助我解决这个问题或太深”你可能已经错过了W3C或谷歌或搜索SO。 – 2011-05-27 19:27:37

在这个问题看看这里

Is there an XSLT name-of element?

您可以使用

<xsl:value-of select ="name(.)"/> 

<xsl:value-of select ="local-name()"/> 

得到一个节点的名称,这取决于你想要包含完整的前缀名称,或仅包含本地部分。

您应该可以将这些与xsl:for-each块一起拼凑起来,以迭代项目的前三个级别并生成您正在寻找的HTML。

像这样的东西可以适用于固定数量的水平。

<xsl:for-each select="*"> 
     <html> 
      <head> 
       <title><xsl:value-of select="local-name()" /></title> 
      </head> 
      <body> 
       <div class="root"> 
        <xsl:for-each select="*"> 
         <div> 
          <xsl:attribute name="class"> 
           <xsl:value-of select="local-name()" /> 
          </xsl:attribute> 
          <xsl:for-each select="*"> 
           <b><xsl:value-of select="local-name()" />:</b> <xsl:value-of select="." /> 
          </xsl:for-each> 
         </div> 
        </xsl:for-each> 
       </div> 
      </body> 
     </html> 
    </xsl:for-each> 

一个更通用的方法会看起来更象:

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

<xsl:output method="html" indent="yes" version="4.0"/> 
<xsl:template match="/"> 
    <xsl:for-each select="*"> 
     <html> 
      <head> 
       <title><xsl:value-of select="local-name()" /></title> 
      </head> 
      <body> 
       <div class="root"> 
         <xsl:call-template name="recurseElement"> 
          <xsl:with-param name="element" select="." /> 
         </xsl:call-template> 
       </div> 
      </body> 
     </html> 
    </xsl:for-each> 
</xsl:template> 
<xsl:template name="recurseElement"> 
    <xsl:param name="element" /> 
    <xsl:for-each select="$element/*"> 
     <xsl:choose> 
       <xsl:when test="count(child::*)>0"> 
        <div> 
         <xsl:attribute name="class"> 
          <xsl:value-of select="local-name()" /> 
         </xsl:attribute> 
         <xsl:call-template name="recurseElement"> 
          <xsl:with-param name="element" select="." /> 
         </xsl:call-template> 
        </div> 
       </xsl:when> 
       <xsl:otherwise> 
        <b><xsl:value-of select="local-name()" />:</b> <xsl:value-of select="." /> 
       </xsl:otherwise> 
     </xsl:choose> 
    </xsl:for-each> 
</xsl:template> 
</xsl:stylesheet> 
+0

请原谅我的无知,但是代码不会创建多个HTML文档,或者更确切地说,是不是它会在html文档中创建多个html元素?当然,这会使其无效,因为html文档可能只有一个html元素。 – FNj 2011-05-27 20:05:36

+0

如果源XML文档有多个根节点(这将是无效的XML),则底部的xslt只会生成多个HTML文档。在这种情况下,第一个循环可能已被替换为'xsl:for-each select =“/”',如果这样做更有意义。我特意处理根目录并将其包装在HTML中的原因是因为该示例显示了用作HTML文档的根元素的名称

,所以我试图重现该原因。没有更详细的描述,这是我对预期产出的最好猜测。 – <span class="text-secondary"> <small> <a rel="noopener">tschaible</a></small></span> <span>2011-05-27 22:13:48</span>

这个完整的XSLT转换

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="AddressBook"> 
    <html> 
    <head> 
    <title>AddressBook</title> 
    </head> 
    <body> 
     <div class="root"> 
     <xsl:apply-templates/> 
     </div> 
    </body> 
    </html> 
</xsl:template> 

<xsl:template match="Item"> 
    <div class="item"><xsl:apply-templates/></div> 
</xsl:template> 

<xsl:template match="Item/*"> 
    <b><xsl:value-of select="name()"/>:</b> <xsl:text/> 
    <xsl:value-of select="concat(.,'&#xA;   ')"/> 
</xsl:template> 
</xsl:stylesheet> 

时所提供的XML文档应用:

<AddressBook> 
    <Item> 
     <UserGeneratedElementName1 class="info">Whatever blah blah</UserGeneratedElementName1> 
     <UserGeneratedElementName2 class="info">Whatever blah blah</UserGeneratedElementName2> 
    </Item> 
    <Item> 
     <UserGeneratedElementName3 class="info">Whatever blah blah</UserGeneratedElementName3> 
    </Item> ... ... Other Items with user-generated elements with user-generated content... 
</AddressBook> 

产生想要的,正确的结果

<html> 
    <head> 
     <title>AddressBook</title> 
    </head> 
    <body> 
     <div class="root"> 
     <div class="item"> 
      <b>UserGeneratedElementName1:</b>Whatever blah blah 
      <b>UserGeneratedElementName2:</b>Whatever blah blah 
      </div> 
     <div class="item"> 
      <b>UserGeneratedElementName3:</b>Whatever blah blah 
      </div> ... ... Other Items with user-generated elements with user-generated content... 
</div> 
    </body> 
</html> 

说明

  1. Templates matching任何Item元素和Item元素的任何元素的孩子。

  2. 使用标准XPath name()函数

+0

这条线究竟做了什么? '' – FNj 2011-05-28 08:01:21

+0

@FNj:xsl:select-value-'concat(。,' ')“/>输出串联的使用新行字符(它具有10或十六进制A的代码)将当前节点(即与模板匹配)的steing值。可以使用*字符引用*通过其代码输出任何字符 - 在形成'xxx;'(这是十进制)或'&#xabcd;'(这是十六进制)。 – 2011-05-28 13:59:19