【问题标题】:Add attribute to XML root node using XSLT (and output existing XSLT with HTML?)使用 XSLT 向 XML 根节点添加属性(并使用 HTML 输出现有的 XSLT?)
【发布时间】:2015-10-07 08:49:55
【问题描述】:

我对此表示歉意,因为周围有类似的问题,但是我尝试应用所有这些问题,但无法让我的工作与现有的样式表 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 表? :(

请帮忙。

【问题讨论】:

  • 单个 XSLT (1.0) 样式表创建一个可以序列化为 HTML、XML 或纯文本的结果树。让单个 XSLT 1.0 样式表创建一些 HTML 以及一些可操作的 XML 是不可能的。在 XSLT/XPath 数据模型中,xmlns“属性”甚至不被视为属性,它是一个命名空间声明。所以我不确定我是否理解您想要实现的目标,您可能想要编辑您的问题并显示您想要创建的输出。
  • 基本上,除了我的 html 表之外,我只想要 StockList 的命名空间声明。从你的解释看来这是不可能的。 :s 我没有从 C# 声明它的原因是因为它是一个使用 writexml 来自动化输出的数据集。你不能在那一端附加一个根命名空间,所以我想我可以用 XLST 来做。
  • 如果您使用 C# 通过“writexml”生成 XML,您可以创建一些额外的 C# 来更改 XML 中所有元素的命名空间,然后再将其发送出去。例如,请参阅msdn.microsoft.com/en-gb/library/bb943914.aspx

标签: html xml xslt attributes root


【解决方案1】:

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

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

  1. 修改生成源 XML 的任何内容,以便它为您正确声明 &lt;StockList&gt; 的命名空间。你可以这样做:

    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,使其不关心名称空间。例如,将&lt;xsl:for-each select="aa:StockList/aa:StockItem"&gt; 更改为&lt;xsl:for-each select="*[local-name()='StockList']/*[local-name()='StockItem']"&gt; 等等,只要有select 使用该命名空间前缀。这可能是更容易解决的问题 - 我自己会采用这个解决方案。

【讨论】:

  • 1. 的确,您不能修改现有的 XML - 但您当然可以对其应用两个(或多个)XSL 转换,并行或串行。 -- 2. 几乎从不需要绕过命名空间,而且——根据定义——不是好的做法。
  • @michael.hor257k,我认为不可能在问题的上下文中应用多个转换 - 我假设我们正在谈论浏览器渲染。如果这在这种情况下是可能的,我很想知道。对于 2 来说,使用默认命名空间可能会更好,但听起来他们希望这个样式表处理一些带有 NS 的数据而一些没有。在这种情况下,除了我的建议之外,我不确定要采取哪种方法。
  • 在这些假设下,我同意。由 OP 来澄清。
  • 丹和迈克尔,感谢您的回复。丹,你是正确的假设我只想要一些用 NS 处理的数据而一些没有。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-13
    • 2012-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-12
    • 1970-01-01
    相关资源
    最近更新 更多