查找XPath表达式的相对构造(算法)

时间:2013-07-12 13:28:02

标签: xslt xpath xsd schematron

我遇到了一个有趣的要求,我已经有了自己的工作实施,但我正在努力确保我已经涵盖了所有的角落案例。

我想要实现的目标最好被描述为“XPath条件委派”。

假设某些模糊的模式语言可以使用任意XPath条件约束实例元素。这些条件将转换为Schematron断言,然后应用于XML实例文档。为了使它工作,每个条件都需要一个上下文节点来测试表达式(就像说:“在XML实例文档中找到一个特定的元素,然后检查XPath条件是否适用于它”)。事情是;我的模式语言中的某些条件可能是为虚拟/抽象节点定义的,它们从未出现在实例文档中(xsd:choice在这里可能是一个合适的类比 - 它只存在于语言文件中而不存在于实例中)。所以我想,好吧,让我们简单地将条件从父vitrual节点委托给子节点,实际出现在XML实例中。它结果很棒!如果您只使用绝对XPath位置路径...

模式语言的假设示例:

element smth {
    element c-enabled;
    choice c {
        assert "c-enabled = 'true'"; <!-- context node is <smth>, first instatiable ancestor -->
        element one;
        element two;
    }
    element foo;
}

这基本上说,允许有<smth><c-enabled>孩子的<foo>元素,如果<c-enabled>的值'true'也允许是<one>还是<two>孩子。有效实例文档的示例:

<smth>
    <c-enabled>true</c-enabled>
    <two/>
    <foo/>
</smth>

所以,如前所述,我决定将条件委托给<one><two>,基本上在运行时将上述模式重构为以下模式:

element smth {
    element c-enabled;
    choice c {            
        element one {
            assert "c-enabled = 'true'"; <!-- context node is <one>, never satisfied since <one> has no <c-enabled> child -->
        }
        element two {
            assert "c-enabled = 'true'"; <!-- context node is <two>, never satisfied since <two> has no <c-enabled> child -->
        }
    }
    element foo;
}

如果使用绝对路径编写XPath条件,这显然只会起作用。每次在实例文档中遇到<one><two>时,都会使用它们作为初始上下文节点来检查条件(它们是current()在XSLT中返回的内容)。

所以在阅读了一些XPath specification并使用精彩的ANTLR4 tool结合this grammar并实现转换解析树walker创建XPath解析器后,我现在正在将原始架构重构为此:

element smth {
    element c-enabled;
    choice c {            
        element one {
            assert "../c-enabled = 'true'"; <!-- u-huh, this is what we're after -->
        }
        element two {
            assert "../c-enabled = 'true'"; <!-- u-huh, this is what we're after -->
        }
    }
    element foo;
}

请注意,这只是我正在处理的XPath条件的一个简单示例(这不是简单地编写正则表达式来处理它),因为它们完全是任意的,由创建模式定义的任何人组成。我唯一可以肯定的是它们是有效的XPath 1.0表达式(仅基函数,没有变量)。


所以我的问题是:根据XPath 1.0规范,XPath表达式中哪些位置可能会出现引用初始上下文节点(以相对方式)的构造?

我目前的假设是:任何RelativeLocationPath在解析树中没有以下任何祖先:AbsoluteLocationPathPredicate。如果RelativeLocationPath前面有AbsoluteLocationPath,则组合形成绝对构造。在谓词中,所有路径都指向不同的上下文节点,或者是绝对的。

我假设这是基于我制作的这个图表(表示在使用我参考上面提到的语法解析XPath时如何调用产品): Grammar graph


以下是我需要在XPath表达式中找到的地方的一些示例。基本上寻找这些(以及可能的其他)的正式定义。

(../area-type = 'stub') or (../area-type = 'nssa')
 ^                          ^
(../../../cacheMode != 'ipfix:immediate')
 ^
address-family='ipV4' and safi='nlri-unicast'
^                         ^
(../../../cacheMode != 'ipfix:immediate') and ((count(../ieEnterpriseNumber) = 0) or (../ieEnterpriseNumber != 29305))
 ^                                                    ^                               ^

1 个答案:

答案 0 :(得分:1)

您的分析在初读时听起来似乎合理,但由于您正在寻找角落案件,因此很大程度上取决于您的意思。如果你的意思是“在语法中的地方,那么。并且......引用初始上下文项目,而不是以某种其他方式设置的上下文项目”那么(假设“以某种其他方式设置”)在某些方面被定义和理解合适的方式)你的表征似乎是正确的但那些并不是唯一的地方。和..可以引用初始上下文项或其父项:考虑./. - 两个点都指向同一节点,这是初始上下文项。或./*/../. - 等等。

如果我理解您的想法,您希望接受与特定节点关联的XPath表达式,但不是使用该节点作为当前节点评估它们,而是希望将适当的表达式传递给其他节点以使用进行评估那些节点作为上下文项。

如果你将自己限制在路径表达式中,并且你的委托总是要么是抽象类的实例化,要么是子项的实例化,那么(a)绝对路径表达式和相对路径表达式之间的区别很容易识别,(b)路径表达式的必要修改很容易描述(没有更改或添加'../'到开头)。如果你允许更一般的表达 - 例如函数调用 - 您将不得不理解表达式结构和更复杂的调整。如果用户写local-name() = 'barracuda'并且由于某种原因将其委托给孩子,那么孩子需要评估local-name(..) = 'barracuda'。 (在XPath 2.0中,我想预先添加../会起作用,但我认为不是1.0。)

您还可以在文献中找到有关XPath表达式的流式评估的相关注意事项。