转换包含属性值中的逻辑运算符的XML文件。

时间:2019-07-16 06:09:38

标签: xml xslt

我正在尝试在具有逻辑运算符作为属性值的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>

实现这一目标的最明智的方法是什么?预先感谢!

1 个答案:

答案 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>

示例https://xsltfiddle.liberty-development.net/ncdD7nf/1