XSD 中的 X-Path 2.0 (assert): "count(//elem/text() = 'test') > 0" 始终为真,即使字符串不匹配

Posted

技术标签:

【中文标题】XSD 中的 X-Path 2.0 (assert): "count(//elem/text() = \'test\') > 0" 始终为真,即使字符串不匹配【英文标题】:X-Path 2.0 in XSD (assert): "count(//elem/text() = 'test') > 0" always true, even if string does not matchXSD 中的 X-Path 2.0 (assert): "count(//elem/text() = 'test') > 0" 始终为真,即使字符串不匹配 【发布时间】:2016-09-05 14:57:40 【问题描述】:

我想使用 XSD1.1 断言功能在内容级别验证元素。 (更准确地说,我想检查以 XML 表示的 EDIFACT 中是否存在内容组合,但这不是重点……)

为了测试我的 XPath,我构建了以下小型测试场景:

XML

<root>
    <group>
        <elem1>test1</elem1>
        <elem2>test2</elem2>
    </group>
    <group>
        <elem1>something1</elem1>
        <elem2>something2</elem2>
    </group>
    <group>
        <elem1>other1</elem1>
        <elem2>other2</elem2>
    </group>
</root>

要求是:我要检查,我有 test1 + test2 字符串的组合,以及 something1 和 something2 字符串的组合。可能有像other1 + other2这样的组,可以有,但我不在乎。这里三组的顺序也应该没有影响。

我要测试的 XSD 是:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="root">
    <xsd:complexType>
      <xsd:sequence>

        <xsd:element name="group" minOccurs="1" maxOccurs="unbounded">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="elem1" minOccurs="1">
              </xsd:element>
              <xsd:element name="elem2" minOccurs="1">
              </xsd:element>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>

      </xsd:sequence>
      <xsd:assert test="(count(./group/elem1/text() = 'test1') > 0 
                         and count(./group/elem2/text() = 'test2') > 0) 
                         and (count(./group/elem1/text() = 'something1') > 0 
                         and count(./group/elem2/text() = 'something2') > 0)"/>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

有趣的是:

(count(./group/elem1/text() = 'test1') > 0 
and count(./group/elem2/text() = 'test2') > 0) 
and (count(./group/elem1/text() = 'something1') > 0 
and count(./group/elem2/text() = 'something2') > 0)

或将其分解:

count(./group/elem1/text() = 'test1') > 0

我的问题是:表达式(更具体的计数)返回 true,即使字符串不匹配。假设,我针对“test1”进行测试,但我的字符串是“test”:

./group/elem1/text() = 'test1'

在它自己工作。它正确地返回真或假。但是对它使用 count 是行不通的。 (似乎总是返回 true)

我认为,count 在这里不是正确的解决方案,问题是,我不想在“完全正确”上测试每个组,但毕竟所有组“这个和这个特定组合至少发生一次”在组的所有重复。

我正在 Saxon 9 EE 上对此进行测试,但 XPath 在其他 XPath 实现中也具有相同的行为。

任何帮助将不胜感激。

谢谢你, e


编辑:

在 Mads Hansen 和 Michael Kay(谢谢!)的帮助下完成这项工作后,我还有最后一个障碍要跳过:

考虑这种情况:

<root>
    <group>
        <elem1>test1</elem1>
        <elem2>WRONG</elem2>
    </group>
    <group>
        <elem1>WRONG</elem1>
        <elem2>test2</elem2>
    </group>
</root>

使用此 XPath

count(group[elem1/text() = 'test1' and elem2/text() = 'test2']) > 0)

现在这导致上面的示例无效(如我所愿),而我已经验证了上面的原始 XPath,因为它没有在 .

【问题讨论】:

【参考方案1】:

您需要调整 XPath 以过滤您要查找的项目,然后计算剩下的内容。您当前的表达式正在评估是否有任何 group/elem1/text() 节点等于 test1,这将是 true()false(),然后您正在计算布尔值。

使用谓词测试text() 值并计算有多少满足条件:

count(./group/elem1/text()[.='test1'])

【讨论】:

count(./group/elem1[text() = 'test1'])有区别吗? 注意,您可以将test="count(./x/y[text() = 'TTT']) &gt; 0"简化为test="x/y = 'TTT'" MadsHansen, splash58 @MichaelKay 谢谢你的回答。我现在收到来自 Saxon 的消息“要使用 XPath 3.1 语法,您必须配置 XPath 解析器来处理它”,但我没有在文档中找到启用它的选项。我目前这样称呼验证:/opt/..../_jvm/bin/java -cp "/home/..../test_saxon_ee/saxon9ee.jar" com.saxonica.Validate -t -xsdversion:1.1 -xsd:assert.xsd assert.xml . @eee,究竟是什么 XPath 表达式触发了这条消息? 谓词“[text() = ...]”前的“/”是错误的,应该去掉。错误消息是因为在 XPath 3.1 中,“/”之后的“[”变得合法,尽管它并不意味着您想要它的意思。【参考方案2】:

答案:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:element name="root">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="group" minOccurs="1" maxOccurs="unbounded">
                    <xsd:complexType>
                        <xsd:sequence>
                            <xsd:element name="elem1" minOccurs="1">
                            </xsd:element>
                            <xsd:element name="elem2" minOccurs="1">
                            </xsd:element>
                        </xsd:sequence>
                    </xsd:complexType>
                </xsd:element>

                </xsd:sequence>
                <xsd:assert test="(count(group[elem1/text() = 'test1' 
                                and elem2/text() = 'test2']) > 0) 
                                and (count(group[elem1/text() = 'something1' 
                                and elem2/text() = 'something2']) > 0 )"/>
            </xsd:complexType>
        </xsd:element>
    </xsd:schema>

将验证:

<root>
    <group>
        <elem1>test1</elem1>
        <elem2>test2</elem2>
    </group>
    <group>
        <elem1>test1</elem1>
        <elem2>test4</elem2>
    </group>
    <group>
        <elem1>something1</elem1>
        <elem2>something2</elem2>
    </group>
    <group>
        <elem1>other1</elem1>
        <elem2>other2</elem2>
    </group>
</root>

【讨论】:

以上是关于XSD 中的 X-Path 2.0 (assert): "count(//elem/text() = 'test') > 0" 始终为真,即使字符串不匹配的主要内容,如果未能解决你的问题,请参考以下文章

X-PATH定位元素

XML Schema 1.1无法识别'assert'或'assertion'

C#:读取 XML 属性

Jaxb 2.0 Schema 验证问题

XSD 中的循环依赖是不是有效?

在 PHP 中解析 XSD 文件并显示 XSD 中的元素