我正在尝试在具有逻辑运算符作为属性值的XML文件上创建XSLT转换。 我的问题,创建此XSLT转换是否超级复杂,还是我必须从头开始编写某种“处理器”来理解我属性中的这些逻辑运算符?
这是我希望它如何工作的一个示例:
我有一个示例XML,如下所示:
<book>
<chapter condition="A and B">Chapter 1</chapter>
<chapter condition="not B">Chapter 2</chapter>
<chapter condition="A or D">Chapter 3</chapter>
<chapter condition="not C">Chapter 4</chapter>
<chapter condition="D and (B or C)">Chapter 5</chapter>
<chapter condition="D">Chapter 6</chapter>
</book>
然后我有一个值列表“ 值= [B,D] ”,我想遍历此列表并删除那些与该值“不匹配”的章节列表。
因此,考虑以下值: [B,D] ,转换后的输出XML如下所示:
<book>
#This would get removed, seeing as it requires both A and B values.
<chapter condition="A and B">Chapter 1</chapter>
#This would also get removed, seeing as the attribute is "not B", so
if B value is present, it gets removed.
<chapter condition="not B">Chapter 2</chapter>
#This chapter would stay, the value D is present.
<chapter condition="A or D">Chapter 3</chapter>
#This chapter would also stay, as the value C is not in our list.
<chapter condition="not C">Chapter 4</chapter>
#In this case this chapter would stay, seeing as we have value D and B.
<chapter condition="D and (B or C)">Chapter 5</chapter>
#This chapter would stay, as value D is present in our list.
<chapter condition="D">Chapter 6</chapter>
</book>
实现这一目标的最明智的方法是什么?预先感谢!
答案 0 :(得分:0)
如果您可以调整语法以使用XPath not()
函数/运算符,并且我们可以假定列表中所有大写字母序列均表示布尔值true,则不表示布尔值如果为false,则可以对根据您的条件创建的表达式在XSLT 3中对xsl:evaluate
使用动态XPath评估:
所以输入
<?xml version="1.0" encoding="UTF-8"?>
<book>
<chapter condition="A and B">Chapter 1</chapter>
<chapter condition="not(B)">Chapter 2</chapter>
<chapter condition="A or D">Chapter 3</chapter>
<chapter condition="not(C)">Chapter 4</chapter>
<chapter condition="D and (B or C)">Chapter 5</chapter>
<chapter condition="D">Chapter 6</chapter>
</book>
使用Saxon 9.7或更高版本的PE或EE或任何其他支持xsl:evaluate
的XSLT 3处理器,可以使用
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com"
exclude-result-prefixes="#all"
version="3.0">
<xsl:param name="true-values" as="xs:string*" select="'B', 'D'"/>
<xsl:function name="mf:substitute-variables" as="xs:string">
<xsl:param name="expression" as="xs:string"/>
<xsl:variable name="substituted-expression" as="xs:string*">
<xsl:apply-templates select="analyze-string($expression, '\p{Lu}+')" mode="substitution"/>
</xsl:variable>
<xsl:sequence select="string-join($substituted-expression)"/>
</xsl:function>
<xsl:template match="*:match[not(. = $true-values)]" mode="substitution">
<xsl:text>false()</xsl:text>
</xsl:template>
<xsl:template match="*:match[. = $true-values]" mode="substitution">
<xsl:text>true()</xsl:text>
</xsl:template>
<xsl:function name="mf:evaluate-condition" as="xs:boolean">
<xsl:param name="expression" as="xs:string"/>
<xsl:evaluate xpath="$expression"/>
</xsl:function>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml"/>
<xsl:template match="chapter[@condition and not(mf:evaluate-condition(mf:substitute-variables(@condition)))]"/>
</xsl:stylesheet>
到
<book>
<chapter condition="A or D">Chapter 3</chapter>
<chapter condition="not(C)">Chapter 4</chapter>
<chapter condition="D and (B or C)">Chapter 5</chapter>
<chapter condition="D">Chapter 6</chapter>
</book>
假设XSLT支持XPath 3.1 transform
函数,则可以避免使用xsl:evaluate
(仅在Saxon 9的商业版本中可用,而transform
在9.8及更高版本的开源HE),并即时构建包含必要条件的样式表:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com"
exclude-result-prefixes="#all"
version="3.0">
<xsl:param name="true-values" as="xs:string*" select="'B', 'D'"/>
<xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>
<xsl:function name="mf:substitute-variables" as="xs:string">
<xsl:param name="expression" as="xs:string"/>
<xsl:variable name="substituted-expression" as="xs:string*">
<xsl:apply-templates select="analyze-string($expression, '\p{Lu}+')" mode="substitution"/>
</xsl:variable>
<xsl:sequence select="string-join($substituted-expression)"/>
</xsl:function>
<xsl:template match="*:match[not(. = $true-values)]" mode="substitution">
<xsl:text>false()</xsl:text>
</xsl:template>
<xsl:template match="*:match[. = $true-values]" mode="substitution">
<xsl:text>true()</xsl:text>
</xsl:template>
<xsl:mode name="template" on-no-match="shallow-copy"/>
<xsl:variable name="stylesheet">
<axsl:stylesheet version="3.0">
<axsl:mode on-no-match="shallow-copy"/>
<xsl:apply-templates select="//chapter[@condition]" mode="template"/>
</axsl:stylesheet>
</xsl:variable>
<xsl:template match="chapter[@condition]" mode="template">
<axsl:template match="chapter[@condition = '{@condition}']">
<axsl:if test="{mf:substitute-variables(@condition)}">
<axsl:next-match/>
</axsl:if>
</axsl:template>
</xsl:template>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:sequence
select="transform(
map {
'source-node' : .,
'stylesheet-node' : $stylesheet
}
)?output"/>
</xsl:template>
</xsl:stylesheet>
仍然假定not
运算符以XPath样式使用,并且使用正则表达式可以将“变量”名称(例如'A','B')进行一些文本转换为布尔值。 https://xsltfiddle.liberty-development.net/ncdD7nf上的在线示例。
关于将其应用于更多元素,我建议在提供XPath表达式的地方声明一个全局参数,以选择这些参数并将其用于生成XSLT的代码中:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com"
exclude-result-prefixes="#all"
version="3.0">
<xsl:param name="true-values" as="xs:string*" select="'B', 'D', 'YES'"/>
<xsl:param name="elements-to-be-transformed" select="//chapter[@condition], //chapter/title[@condition]"/>
<xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>
<xsl:function name="mf:substitute-variables" as="xs:string">
<xsl:param name="expression" as="xs:string"/>
<xsl:variable name="substituted-expression" as="xs:string*">
<xsl:apply-templates select="analyze-string($expression, '\p{Lu}+')" mode="substitution"/>
</xsl:variable>
<xsl:sequence select="string-join($substituted-expression)"/>
</xsl:function>
<xsl:template match="*:match[not(. = $true-values)]" mode="substitution">
<xsl:text>false()</xsl:text>
</xsl:template>
<xsl:template match="*:match[. = $true-values]" mode="substitution">
<xsl:text>true()</xsl:text>
</xsl:template>
<xsl:mode name="template" on-no-match="shallow-copy"/>
<xsl:variable name="stylesheet">
<axsl:stylesheet version="3.0">
<axsl:mode on-no-match="shallow-copy"/>
<xsl:apply-templates select="$elements-to-be-transformed" mode="template"/>
</axsl:stylesheet>
</xsl:variable>
<xsl:template match="*[@condition]" mode="template">
<axsl:template match="{node-name()}[@condition = '{@condition}']">
<axsl:if test="{mf:substitute-variables(@condition)}">
<axsl:next-match/>
</axsl:if>
</axsl:template>
</xsl:template>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:sequence
select="transform(
map {
'source-node' : .,
'stylesheet-node' : $stylesheet
}
)?output"/>
</xsl:template>
</xsl:stylesheet>