直接从代码调用特定模板

时间:2016-03-08 15:35:21

标签: .net xslt

从.NET代码可以直接调用特定的XSLT模板吗? 即通常给出的代码如下: (VB.Net抱歉,这是旧代码!)

Dim xsl As New System.Xml.Xsl.XslCompiledTransform()
xsl.Load(SomeXSLFile)
xsl.Transform(SomeXML, SomeArgs, SomeOutput)

引擎将根据与XML文档匹配的内容处理XSL文件中的所有模板。

但是作为我的XSL文件的一部分,我有一个命名模板:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <xsl:text>Some output</xsl:text>
    <xsl:call-template name="Boilerplate"/>
  </xsl:template>
  <xsl:template name="Boilerplate">
    <xsl:text>Generated by XSL</xsl:text>
  </xsl:template>
</xsl:stylesheet>

是否有办法直接从.NET代码调用此命名模板(提供文档或假设空文档)

我可以通过在XSL中使用规则来检测特定的XML模式(例如<CallTemplate name="Boilerplate"/>)并采取相应的行动,但希望有更自然的方法来解决这个问题吗?

2 个答案:

答案 0 :(得分:2)

实际上,没有办法直接执行此操作,但可以使用xsl:include或xsl:import创建包含目标样式表的样式表,然后调用命名模板。像这样:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:import href="(your stylesheet)"/>

  <xsl:template match="/">
    <xsl:call-template name="(template name)"/>
  </xsl:template>
</xsl:stylesheet>

我很少使用xsl:include或xsl:import但我真的不能100%确定这是如何工作的,模板匹配可能会有一个优先顺序问题&#34; \&# 34;在这个样式表和你的样式表之间,但希望这能为你指明一个有用的方向。

答案 1 :(得分:0)

与Flynn1179的答案类似,我改为采用现有的XSL文件,将match = / template替换为只调用命名模板的文件。

此代码非常粗糙,应在使用前进行整理。 此外,它假定只传入一个XMLReader,但不检查它。

Private Shared dicStaticTemplateContent As New Dictionary(Of String, String)
Private Shared Function GetStaticTemplateContent(xmrXSLFile As System.Xml.XmlReader, strTemplateName As String) As String
    If Not dicStaticTemplateContent.ContainsKey(strTemplateName) Then
        Dim xmd As New System.Xml.XmlDocument
        xmd.Load(xmrXSLFile)
        Dim nsm As New System.Xml.XmlNamespaceManager(xmd.NameTable)
        nsm.AddNamespace("xsl", "http://www.w3.org/1999/XSL/Transform")
        Dim xmnRootTemplate As System.Xml.XmlNode = xmd.SelectSingleNode("/xsl:stylesheet/xsl:template[@match='/']", nsm)
        Dim xmeNewRoot As System.Xml.XmlElement = xmd.CreateElement("template", "http://www.w3.org/1999/XSL/Transform")
        If (xmnRootTemplate Is Nothing) Then
            xmnRootTemplate = xmd.SelectSingleNode("/xsl:stylesheet/xsl:template[1]", nsm)
            If (xmnRootTemplate Is Nothing) Then
                xmd.DocumentElement.AppendChild(xmeNewRoot) 'quite pointless actually, if there are no templates then the thing won't work anyway, but this is a shortcut towards providing a somewhat more meaningful error anyway (from the xsl engine)
            Else
                xmd.DocumentElement.InsertBefore(xmeNewRoot, xmnRootTemplate)
            End If
        Else
            xmnRootTemplate.ParentNode.ReplaceChild(xmeNewRoot, xmnRootTemplate)
        End If
            xmeNewRoot.InnerXml = "<xsl:call-template name=""" + strTemplateName + """/>"
            xmeNewRoot.SetAttribute("match", "/")

            Dim xsl As New System.Xml.Xsl.XslCompiledTransform()
            Dim xss As New System.Xml.Xsl.XsltSettings(True, True)
            xsl.Load(xmd, xss, Nothing)

            Dim strResult = ProcessTransform(xmd, xsl, Nothing, Nothing)

            dicStaticTemplateContent.Add(strTemplateName, strResult)
        End If
    Return dicStaticTemplateContent(strTemplateName)
End Function

并非所有代码路径都经过测试(特别是没有匹配= /模板的地方)

另外,请注意模板名称上的注入攻击