布尔表达式的XSLT转换

时间:2015-12-15 23:09:23

标签: xslt transformation

我对XSLT世界很陌生,需要以下方面的帮助: 程序采用以下字符串:

cn ='James Bond'和(sn ='Bon *'或givenName ='Jam *')

并生成以下XML,这是我需要使用样式表处理的输入XML。

输入XML:

<?xml version="1.0" encoding="UTF-8"?>
<queryString>
    <parameters>
        <parameter id = "1">
            <name>cn</name>
            <value>James Bond</value>
            <comparativeOperator>=</comparativeOperator>
            <parens>
                <leftParen>((</leftParen>
                <rightParen>)</rightParen>
            </parens>
        </parameter>
        <parameter id = "25">
            <name>sn</name>
            <value>Bon*</value>
            <comparativeOperator>=</comparativeOperator>
            <parens>
                <leftParen>((</leftParen>
                <rightParen>)</rightParen>
            </parens>
        </parameter>
        <parameter id = "50">
            <name>givenName</name>
            <value>Jam*</value>
            <comparativeOperator>=</comparativeOperator>
            <parens>
                <leftParen>(</leftParen>
                <rightParen>)))</rightParen>
            </parens>
        </parameter>
    </parameters>
    <logicalOperators>
        <operator id = "20">
            <value>and</value>
            <precedingParameterId>1</precedingParameterId>
            <followingParameterId>25</followingParameterId>
        </operator>
        <operator id = "46">
            <value>or</value>
            <precedingParameterId>25</precedingParameterId>
            <followingParameterId>50</followingParameterId>
        </operator>
    </logicalOperators>
</queryString>

期望输出:

<?xml version="1.0" encoding="UTF-8"?>
    <ns0:filter>
        <ns0:and>
          <ns0:or>
            <ns0:equalityMatch name="cn">
                <ns0:value>James Bond</ns0:value>
            </ns0:equalityMatch>
          </ns0:or>
          <ns0:or>
            <ns0:approxMatch name="givenName">
                <ns0:value>Jam*</ns0:value>
            </ns0:approxMatch>
            <ns0:approxMatch name="sn">
                <ns0:value>Bon*</ns0:value>
            </ns0:approxMatch>
          </ns0:or>
        </ns0:and>
    </ns0:filter>

我现有的xslt 如下:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:ns0="urn:oasis:names:tc:DSML:2:0:core" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="ns0">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/queryString/logicalOperators/operator">
        <ns0:filter>
            <MyOp>
                <xsl:value-of select="value"/>
            </MyOp>             
            <xsl:for-each select="../../parameters/parameter">
                <xsl:if test="comparativeOperator = '='">
                    <ns0:equalityMatch name="{name}">
                        <value>
                            <xsl:value-of select="value"/>
                        </value>
                    </ns0:equalityMatch>
                </xsl:if>
            </xsl:for-each>
        </ns0:filter>
        <!--/xsl:element-->
    </xsl:template>
    <xsl:template match="parens">
        <xsl:element name="leftParensoutput">
            <xsl:value-of select="leftParen"/>
        </xsl:element>
        <xsl:element name="rightParensoutput">
            <xsl:value-of select="rightParen"/>
        </xsl:element>
    </xsl:template>
    <xsl:template match="parameters/parameter">
        <xsl:element name="FilterParameters">
            <xsl:apply-templates select="parens"/>
            <xsl:element name="queryfilterParameterElement">
                <xsl:element name="id">
                    <xsl:value-of select="@id"/>
                </xsl:element>
                <xsl:element name="name">
                    <xsl:value-of select="name"/>
                </xsl:element>
                <xsl:element name="value">
                    <xsl:value-of select="value"/>
                </xsl:element>
            </xsl:element>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

当前输出:

<?xml version="1.0" encoding="UTF-8"?>
<FilterParameters>
    <leftParensoutput>((</leftParensoutput>
    <rightParensoutput>)</rightParensoutput>
    <queryfilterParameterElement>
        <id>1</id>
        <name>cn</name>
        <value>James Bon*</value>
    </queryfilterParameterElement>
</FilterParameters>
<FilterParameters>
    <leftParensoutput>((</leftParensoutput>
    <rightParensoutput>)</rightParensoutput>
    <queryfilterParameterElement>
        <id>25</id>
        <name>sn</name>
        <value>Bon*</value>
    </queryfilterParameterElement>
</FilterParameters>
<FilterParameters>
    <leftParensoutput>(</leftParensoutput>
    <rightParensoutput>)))</rightParensoutput>
    <queryfilterParameterElement>
        <id>50</id>
        <name>givenName</name>
        <value>Jam*</value>
    </queryfilterParameterElement>
</FilterParameters>
<ns0:filter xmlns:ns0="urn:oasis:names:tc:DSML:2:0:core">
    <MyOp>and</MyOp>
    <ns0:equalityMatch name="cn">
        <value>James Bon*</value>
    </ns0:equalityMatch>
    <ns0:equalityMatch name="sn">
        <value>Bon*</value>
    </ns0:equalityMatch>
    <ns0:equalityMatch name="givenName">
        <value>Jam*</value>
    </ns0:equalityMatch>
</ns0:filter>
<ns0:filter xmlns:ns0="urn:oasis:names:tc:DSML:2:0:core">
    <MyOp>or</MyOp>
    <ns0:equalityMatch name="cn">
        <value>James Bon*</value>
    </ns0:equalityMatch>
    <ns0:equalityMatch name="sn">
        <value>Bon*</value>
    </ns0:equalityMatch>
    <ns0:equalityMatch name="givenName">
        <value>Jam*</value>
    </ns0:equalityMatch>
</ns0:filter>

我正在处理多个问题。我不确定是否需要分开问题,但决定提出整个问题。

提前致谢!

i)当我遍历logicalOperators时,如何将previousParameterId与under参数匹配。

ii)在所需的输出中,如何创建节点: - 即。动态添加“ns0”并获取参数/运算符

的“值”

iii))我不知道如何删除无关的FilterParameters元素。如果我删除该部分,我的输出如下:

<?xml version="1.0" encoding="UTF-8"?>**cnJames Bon*=(()snBon*=(()givenNameJam*=()))**<ns0:filter xmlns:ns0="urn:oasis:names:tc:DSML:2:0:core">
    <MyOp>and</MyOp>
    <ns0:equalityMatch name="cn">
        <value>James Bon*</value>
    </ns0:equalityMatch>
    <ns0:equalityMatch name="sn">
        <value>Bon*</value>
    </ns0:equalityMatch>
    <ns0:equalityMatch name="givenName">
        <value>Jam*</value>
    </ns0:equalityMatch>
</ns0:filter><ns0:filter xmlns:ns0="urn:oasis:names:tc:DSML:2:0:core">
    <MyOp>or</MyOp>
    <ns0:equalityMatch name="cn">
        <value>James Bon*</value>
    </ns0:equalityMatch>
    <ns0:equalityMatch name="sn">
        <value>Bon*</value>
    </ns0:equalityMatch>
    <ns0:equalityMatch name="givenName">
        <value>Jam*</value>
    </ns0:equalityMatch>
</ns0:filter>

添加逻辑: 椒盐卷饼逻辑如下:
创建根节点; 对于每个queryString / logicalOperators /运算符,创建一个node,其中operator是logicalOperators / operator / value的值;   在此节点内,使用logicalOperators / operator / precedingParameterId和followingParameterId将它们与       queryString / parameters / parameter / parens / leftParen和rightParen;   如果模式相同,则获取queryString / parameters / parameter / name和value并使用ns0:operator标记关闭   这应该

<ns0:equalityMatch name="cn">
    <ns0:value>James Bond</ns0:value>
</ns0:equalityMatch> 

如果它们不相同,则创建一个节点,对于logicalOperators / operator / precedingParameterId,获取相应的    queryString / parameters /参数@id / name和value并关闭;对于logicalOperators / operator / followingParameterId,获取相应的    queryString / parameters /参数@id / name和value并关闭;   这应该给出:

<ns0:or>
<ns0:approxMatch name="givenName">
    <ns0:value>Jam*</ns0:value>
</ns0:approxMatch>
<ns0:approxMatch name="sn">
    <ns0:value>Bon*</ns0:value>
</ns0:approxMatch>

如果queryString / parameters / parameter / value不包含星号使用节点equalityMatch否则使用no​​de approxMatch

1 个答案:

答案 0 :(得分:0)

谁设计了表达式的这种中间XML表示,为什么他们这样做呢?这个XML表示的语法和语义是否定义得很好,还是只是“由示例指定”?它通过左括号和右括号的序列指示运算符优先级的方法是高度特异的。我会说它是由对解析器设计知之甚少的人设计的。

给定一个自由选择,我个人将从原始的自由格式表达式开始,而不是从这个中间XML表示开始。当然,我想知道表达式语言的完整语法 - 目前我们只有一个示例表达式可供使用。它看起来像一个相当简单的语法,如果你知道这个理论,解析XSLT中的简单语法并不困难。在Dimitre Novatchev和Gunther Rademacher的XSLT中有很好的解析器编写示例。

不幸的是,从你的帖子中可以清楚地看出你不了解这个理论,因此我很难找到一条前进的方法,这种方式受到我们对你的知识和经验水平的了解。 / p>

因此,由于解析的词法分析阶段已经完成,让我们把问题看作给定,看看我们可以用你的中间XML表示做什么。问题的唯一困难部分(对我来说:可能还有其他难以理解的部分)是找出如何使用左右parens信息在输出中构建层次表达式树。

如果我们在表达式中使用三个“参数”(通常称为“术语”),我们可以为每个参数分配一个级别编号:分别为1,2,2。这表示最终表达式树中出现的术语深度。通过计算括号,可以从中间输入推导出每个术语的级别:术语的级别为

the sum of the number of left parentheses in this and preceding terms
  minus
the sum of the number of right parentheses in preceding terms
  minus 1

将该计算转换为XSLT术语在很大程度上取决于您使用的是XSLT 1.0还是2.0,而您实际上并未这样说。如果我们假设2.0,那就是

sum((.|preceding-sibling::parameter)/parens/string-length(left-paren))
  -
sum(preceding-sibling::parameter/parens/string-length(right-paren))
  -1 

现在,一旦你获得了级别数,构建一个树就是一个“众所周知”的问题,这是使用分组结构的经典练习。不幸的是,它远远超出了初学者的XSLT水平,但这里也是如此。

给定一系列具有级别编号的元素:

<a level="1"/>
<b level="2"/>
<c level="3"/>
<d level="3"/>
<e level="2"/>

我们可以将它们变成树形结构

<a><b><c/><d/></b><e/></a>

使用递归分组如下。我们编写一个模板,进行一级分组,然后递归调用自己进行下一级:

<xsl:template name="grouping">
  <xsl:param name="input" as="element()*"/>
  <xsl:if test="exists($input)">
    <xsl:variable name="level" select="$input[1]/@level"/>
    <xsl:for-each-group select="$input" 
                        group-starting-with="*[@level=$level]">
      <xsl:copy>
        <xsl:call-template name="grouping">
           <xsl:with-param name="input" 
                           select="current-group()[position() gt 1]"/>
        </xsl:call-template>
      </xsl:copy>
    </xsl:for-each-group>
  </xsl:if>
</xsl:template>

同样,那是使用XSLT 2.0。使用XSLT 1.0的解决方案将变得更加困难。

我已经在这里给了你一个大纲,我很欣赏你的XSLT经验水平,充实它将是非常艰苦的工作。但是,我希望你现在能够更好地理解未来的任务。