使用XSLT将属性添加到XML根节点(并使用HTML输出现有的XSLT?)

时间:2015-10-07 08:49:55

标签: html xml xslt attributes root

我为此道歉,因为周围有类似的问题,但是我试图应用所有这些并且不能让我使用现有的样式表html输出。

我有一个现有的XML和一个具有HTML标记的现有XSLT。

我只想使用XSLT向我的XML根节点添加属性,但仍然输出XSLT HTML。

我该怎么做?

我的XML :(我想在节点中添加xmlns属性:“StockList”)

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="do_it.xsl"?>
<StockList>  
<StockItem>
<Item>AX123</Item>
<Description>Firetruck</Description>
<Count>500</Count>
<Order>No</Order>  
</StockItem>  
</StockList>  

我的XSLT:(do_it.xsl)

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

<xsl:template match="/">  
<html>
<body>
<h2>Things On The Shelf:</h2>
<table border="1">
  <tr bgcolor="#9acd32">
    <th style="text-align:left">Item Code</th>
    <th style="text-align:left">Item Description</th>
    <th style="text-align:left">Current Count</th>
    <th style="text-align:left">On Order?</th>
  </tr>
  <xsl:for-each select="aa:StockList/aa:StockItem">
  <tr>
    <td><xsl:value-of select="aa:Item"/></td>
    <td><xsl:value-of select="aa:Description"/></td>
    <td><xsl:value-of select="aa:Count"/></td>
    <td><xsl:value-of select="aa:Order"/></td>
  </tr>
  </xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

那么我需要对XSLT做什么呢?我需要做什么呢?我尝试了大约15种不同的“应用模板”,但是当我设法添加属性时我不能添加我的html表吗? :(

请帮忙。

2 个答案:

答案 0 :(得分:0)

这有一个XY problem的铃声。请放心,您无法通过XSLT更改源文档,即向其添加新属性,以便您的现有样式表代码可以正常工作。您也无法生成中间文档,然后通过XSLT 1.0对其进行转换(至少据我所知)。

你必须做以下两件事之一:

  1. 修改生成源XML的内容,以便正确地为您声明<StockList>的命名空间。你可以这样做:

    using (MemoryStream ms = new MemoryStream())
    {
        dataSet.WriteXml(ms);
        ms.Position = 0; // reset!
        XDocument xd = XDocument.Load(ms);
        XNamespace aa = "http://www.w3schools.com/MMMXXX";
        foreach (var el in xd.Root.DescendantsAndSelf())
        {
           el.Name = aa.GetName(el.Name.LocalName);
        }
        xd.Root.Add(new XAttribute(XNamespace.Xmlns + "aa", aa);
        xd.Save(ms); // or just return the XDocument.ToString(), or return XDocument.CreateReader() as desired
     }
    
  2. 修改您的XSLT,使其不关心命名空间。例如,将<xsl:for-each select="aa:StockList/aa:StockItem">更改为<xsl:for-each select="*[local-name()='StockList']/*[local-name()='StockItem']">,等等,只要您使用该命名空间前缀select。这可能是更容易解决的问题 - 我自己也会使用这个解决方案。

答案 1 :(得分:0)

如果你想在一个样式表中使用XSLT 1.0应用两个转换,其中第一个添加命名空间(你需要将它添加到所有元素),第二个将第一个结果转换为HTML然后你需要执行使用变量作为结果树片段的一步,然后将该结果树片段转换为应用for-each或其他模板的节点集。使用EXSLT扩展函数exsl:node-sethttp://exslt.org/exsl/functions/node-set/index.html)可以使用大多数XSLT处理器将结果树片段转换为节点集,但是IE使用的MSXML不支持EXSLT函数,只有类似的函数在不同的命名空间中。使用ms:script扩展元素it is however possible to have MSXML support exsl:node-set,完成两个转换的样式表看起来像

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:aa="http://example.com/ns1"
  xmlns:exsl="http://exslt.org/common"
  xmlns:ms="urn:schemas-microsoft-com:xslt"
  exclude-result-prefixes="aa exsl ms"
  version="1.0">

<ms:script language="JScript" implements-prefix="exsl">
this['node-set'] = function(nodeList) {
  return nodeList;
}
</ms:script>

<xsl:variable name="rtf1">
  <xsl:apply-templates mode="add-namespace"/>
</xsl:variable>

<xsl:template match="*" mode="add-namespace">
  <xsl:element name="aa:{local-name()}">
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates mode="add-namespace"/>
  </xsl:element>
</xsl:template>

<xsl:template match="/">  
<html>
<body>
<h2>Things On The Shelf:</h2>
<table border="1">
  <tr bgcolor="#9acd32">
    <th style="text-align:left">Item Code</th>
    <th style="text-align:left">Item Description</th>
    <th style="text-align:left">Current Count</th>
    <th style="text-align:left">On Order?</th>
  </tr>
  <xsl:for-each select="exsl:node-set($rtf1)/aa:StockList/aa:StockItem">
  <tr>
    <td><xsl:value-of select="aa:Item"/></td>
    <td><xsl:value-of select="aa:Description"/></td>
    <td><xsl:value-of select="aa:Count"/></td>
    <td><xsl:value-of select="aa:Order"/></td>
  </tr>
  </xsl:for-each>
</table>
</body>
</html>
</xsl:template>

</xsl:stylesheet>

该示例分别在http://home.arcor.de/martin.honnen/xslt/test2015100701.xml http://home.arcor.de/martin.honnen/xslt/test2015100701.xsl处联机。

在Windows 10上与当前版本的Firefox,Chrome和IE一起工作。不幸的是,Microsoft Edge抱怨XSLT中的错误,我不确定是什么原因导致这种情况,因为像IE 11这样的Edge使用MSXML 6来执行XSLT。为了使它与Edge一起使用,我重写了样式表,不使用ms:script而是使用function-availablexsl:when

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:aa="http://example.com/ns1"
  xmlns:exsl="http://exslt.org/common"
  xmlns:ms="urn:schemas-microsoft-com:xslt"
  exclude-result-prefixes="aa exsl ms"
  version="1.0">

<xsl:variable name="rtf1">
  <xsl:apply-templates mode="add-namespace"/>
</xsl:variable>

<xsl:template match="*" mode="add-namespace">
  <xsl:element name="aa:{local-name()}">
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates mode="add-namespace"/>
  </xsl:element>
</xsl:template>

<xsl:template match="/">
  <xsl:choose>
    <xsl:when test="function-available('exsl:node-set')">
      <xsl:apply-templates select="exsl:node-set($rtf1)/aa:StockList"/>
    </xsl:when>
    <xsl:when test="function-available('ms:node-set')">
      <xsl:apply-templates select="ms:node-set($rtf1)/aa:StockList"/>
    </xsl:when>
    <xsl:otherwise>
      <html>
        <body>
          <p>Your XSLT processor does not support exsl:node-set or ms:node-set.</p>
        </body>
      </html>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="/aa:StockList">  
<html>
<body>
<h2>Things On The Shelf:</h2>
<table border="1">
  <tr bgcolor="#9acd32">
    <th style="text-align:left">Item Code</th>
    <th style="text-align:left">Item Description</th>
    <th style="text-align:left">Current Count</th>
    <th style="text-align:left">On Order?</th>
  </tr>
  <xsl:for-each select="aa:StockItem">
  <tr>
    <td><xsl:value-of select="aa:Item"/></td>
    <td><xsl:value-of select="aa:Description"/></td>
    <td><xsl:value-of select="aa:Count"/></td>
    <td><xsl:value-of select="aa:Order"/></td>
  </tr>
  </xsl:for-each>
</table>
</body>
</html>
</xsl:template>

</xsl:stylesheet>

当然,这也适用于Firefox,Chrome和IE。