我想在XSLT中执行条件包含,但xsl:include是顶级元素。您只能使用xsl:if或xsl:在模板内选择。是否有任何类型的黑客或工作允许条件包含外部文件?我试图使用document()函数,但它无法加载我的外部文件(可能是因为它不符合某些规则使其“有效”)。
我的外部xml文件是一堆xslt代码片段。根据主XSLT文件中变量的值,外部文件中的相应代码应该“复制/粘贴”到位(如C或PHP中的条件包含)。
我的主XSLT文件的流程应按以下方式进行:
$configurationMode
if ( $configurationMode = Standard ) { xsl:include="standard.xml" } else { xsl:include="alt.xml" }
显然我不能像上面那样简单地做到这一点,因此我问为什么会有黑客攻击或解决方法。
答案 0 :(得分:3)
据我所知,当xml解析器解析并编译样式表时,会发生'include'。这意味着在处理包之前不会发生逻辑或表达式评估,因此无法使其成为条件。您需要使条件行为发生在样式表之外。
看看这个http://www.dpawson.co.uk/xsl/sect2/N4760.html#d6065e100
Mike Kay的评论特别帮助:
这已被提出多次。在之前的一个帖子中我们来了 得出结论,用户试图写一个通用的 样式表G然后通过有条件地包括a来专门化它 专用样式表A或B.满足此要求的方法是 让A和B包括G,而不是相反,然后你 有条件地在启动时选择A或B作为主要样式表 转型。
答案 1 :(得分:3)
尝试反转结构:如果你有两个特殊目的模块pink.xsl和blue.xsl,以及一个通用模块baby.xsl,那么而不是尝试导入/包含pink.xsl或blue.xsl之一在baby.xsl中,使用pink.xsl或blue.xsl作为顶级条目样式表,并将这两个中的每一个导入baby.xsl。这就是设计使用的方式,它不是黑客或解决方法。
或者,鉴于您的场景“我的外部xml文件是一堆xslt代码片段”的描述,在您的情况下,更好的方法可能是将这些片段中的样式表作为单独的步骤组装,使用XSLT转换而不是而不是使用xsl:include / xsl:import。
答案 2 :(得分:1)
不确定这是否适用于您的方案,但我还是会把它扔出去。
我过去做过类似的事情,但是我没有做一个有条件的包含,而是根据xsl:when的计算结果在两个文件中的任何一个中调用模板。如果您不想在您的案例中使用模板,请忽略此答案。
例如,假设“父”xslt文件名为 root.xslt ,两个有条件使用的文件名为 child1.xslt 和 child2。 XSLT 即可。假设我想针对名为 status 的节点的值运行条件逻辑。如果值为“CURRENT”,我想在child1.xslt中调用名为 isCurrent 的模板,否则在child2.xslt中调用名为 isNotCurrent 的模板。为了简洁起见,在每种情况下,我只是将模板传递给根节点和所有子节点。
它看起来像这样:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:import href="child1.xslt"/>
<xsl:import href="child2.xslt"/>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="rootNode/status = 'CURRENT'">
<!-- template isCurrent defined in child1.xslt -->
<xsl:apply-templates select="rootNode" mode="isCurrent" />
</xsl:when>
<xsl:otherwise>
<!-- template isNotCurrent defined in child2.xslt -->
<xsl:apply-templates select="rootNode" mode="isNotCurrent" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
希望这至少有点帮助。
答案 3 :(得分:0)
除了已经说过的内容之外,一个可能的解决方案是使补充文件成为简单的,提供内容的XML文件(而不是XSLT文件)。这样,您可以将它们包含在XPath的document()
函数中(将在运行时而不是编译时进行评估)。
然后,您可以根据加载的XML文档的内容更改转换的行为;但是,您无法在包含的文档中提供可执行的XSLT片段。
这取决于您的用例是否这是一个解决方案 - 如果其他文档对转换的控制流有很大的影响,您不希望用纯XML定义它们,因为您基本上会重新实现类似XSLT的东西。但是,当您的文档作为一种配置文件时,您可能需要考虑为它们提供纯XML。
当您遇到document()
问题时,请在文件上使用XML验证程序。错误意味着您的文件不是有效的XML。
答案 4 :(得分:0)
<xsl:variable name="CONDITIONAL" select="ELEMENT/CONDITION"/>
<xsl:variable name="DOCUMENTNAME" select="document(concat($CONDITIONAL,'-DOCUMENT.xml'))/ELEMENT"/>
这个例子是我如何有条件地使用外部文件。我在基本XML中有一个标志,XSL将其用作变量,以帮助指定要拉入模板的另一个文件的名称。一旦在我的情况下定义了该变量,我就用它将其他XML数据拉入生成的输出中。 concat命令强制数据一起提供文件名。
所以当我需要外部XML文件的信息时,我使用'$ DOCUMENTNAME'来引用外部数据。
答案 5 :(得分:0)
添加static parameters后,现在可以在XSLT 3.0中使用。静态参数可以在use-when
的{{1}}属性中使用。
现在我们可以使用默认值xsl:include
声明参数,然后在运行时覆盖我们需要的参数...
false()
以下是使用Saxon-HE v9.7(也使用Saxon-PE 9.5测试)测试的完整工作示例。
XML输入(test.xml)
<xsl:param name="someparam" as="xs:boolean" select="false()"
static="yes" required="no"/>
<xsl:include href="include_me.xsl" use-when="$someparam"/>
主XSLT 3.0 (test_main.xsl)
<doc>
<foo/>
</doc>
首先可能包含XSLT 3.0 (test_inc1.xsl)
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="inc1" as="xs:boolean" select="false()"
static="yes" required="no"/>
<xsl:param name="inc2" as="xs:boolean" select="false()"
static="yes" required="no"/>
<xsl:include href="test_inc1.xsl" use-when="$inc1"/>
<xsl:include href="test_inc2.xsl" use-when="$inc2"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
第二种可能包括XSLT 3.0 (test_inc2.xsl)
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="foo">
<xsl:copy>INCLUDE FILE 1!!!</xsl:copy>
</xsl:template>
</xsl:stylesheet>
命令行(将<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="foo">
<xsl:copy>INCLUDE FILE 2!!!</xsl:copy>
</xsl:template>
</xsl:stylesheet>
设置为true)
inc2
<强>输出强>
java -cp "saxon9he.jar" net.sf.saxon.Transform -s:"test.xml" -xsl:"test_main.xsl" inc2="true"
答案 6 :(得分:0)
我发现有一种方法可以在XSLT 2.0中使用use-when功能有条件地包含文件。
你必须创建一个在运行时通过Application传递的系统属性,就像我使用Java一样,所以我使用命令创建了“Debug”属性来运行我的应用程序:
java -DDebug=yes myAppPath
然后在XSLT中使用此属性来包含条件文件。例如
<xsl:include href="file1.xslt" use-when="system-property('DEBUG') = 'yes'"/>
<xsl:include href="file2.xslt" use-when="system-property('DEBUG') != 'yes'"/>
像那样。
不知道它是否适合所问的场景,但是在XSLT 2.0中有可行的方法。 在XSLT 3.0中,还添加了对局部变量的支持。所以这可以使用局部变量轻松完成。
<强>谢谢, 快乐编码