【问题标题】:XPath - Match optional child elements or empty textXPath - 匹配可选的子元素或空文本
【发布时间】:2013-09-24 00:46:32
【问题描述】:

如果有一个 orderEvents 元素并且该元素有一个不是 orderEvent 或空文本的子节点,我有以下代码应该添加一个错误。测试用例更好地展示了我所追求的。

XPATH 表达式适用于所有情况,除非orderEvents 元素中有空白区域。请参阅下面的测试用例 validVendorPaymentFormat7。这是我的 XPATH 表达式。

"./expectedVendorPaymentTransactions/orderEvents/node()[not(self::orderEvent) or self::text()[normalize-space(.)!='']]"

测试用例:

<TestData>
  <TestcaseList>
    <Testcase>
      <rootIdentifier>validVendorPaymentFormat1</rootIdentifier>
      <expectedVendorPaymentTransactions>
        <orderEvents></orderEvents>
      </expectedVendorPaymentTransactions>
    </Testcase>
    <Testcase>
      <rootIdentifier>validVendorPaymentFormat2</rootIdentifier>
    </Testcase>
    <Testcase>
      <rootIdentifier>validVendorPaymentFormat3</rootIdentifier>
      <expectedVendorPaymentTransactions>
      </expectedVendorPaymentTransactions>
    </Testcase>
    <Testcase>
      <rootIdentifier>validVendorPaymentFormat4</rootIdentifier>
      <expectedVendorPaymentTransactions>
        <orderEvents><orderEvent>SOME_EVENT</orderEvent></orderEvents>
      </expectedVendorPaymentTransactions>
    </Testcase>
     <Testcase>
      <rootIdentifier>validVendorPaymentFormat5</rootIdentifier>
      <expectedVendorPaymentTransactions>
        <orderEvents><orderEvent>SOME_EVENT</orderEvent></orderEvents>
      </expectedVendorPaymentTransactions>
    </Testcase>
    <Testcase>
      <rootIdentifier>validVendorPaymentFormat6</rootIdentifier>
      <expectedVendorPaymentTransactions>
        <orderEvents><orderEvent>SOME_EVENT</orderEvent><orderEvent>SOME_EVENT</orderEvent></orderEvents>
      </expectedVendorPaymentTransactions>
    </Testcase>
    <Testcase>
      <rootIdentifier>validVendorPaymentFormat7</rootIdentifier>
      <expectedVendorPaymentTransactions>
        <orderEvents>
          <orderEvent>SOME_EVENT</orderEvent>
        </orderEvents>
      </expectedVendorPaymentTransactions>
    </Testcase>
  </TestcaseList>
</TestData>

失败案例是validVendorPaymentFormat7

失败消息:

[exec] Failure:
 [exec]   Order vendor payments format contains elements other than orderEvent for validVendorPaymentFormat7 ["\n          ", "\n        "].
 [exec]   <false> is not true.

将失败的情况改为:

        <Testcase>
          <rootIdentifier>validVendorPaymentFormat7</rootIdentifier>
          <expectedVendorPaymentTransactions>
            <orderEvents><orderEvent>SOME_EVENT</orderEvent></orderEvents>
          </expectedVendorPaymentTransactions>
        </Testcase>

通过。

不幸的是,http://www.freeformatter.com/xpath-tester.html 测试用例 #7 按预期返回一个空列表。

更新 - 添加代码
Ruby 版本:1.9
irb -v = 0.9.6

测试文件:

require 'rexml/document'

xpath = "//expectedVendorPaymentTransactions/orderEvents/node()[not(self::orderEvent) or self::text()[translate(., ' &#10;', '')!='']]"
document = REXML::Document.new <<EOF 
    <Testcase>
      <rootIdentifier>validVendorPaymentFormat7</rootIdentifier>
      <expectedVendorPaymentTransactions>
        <orderEvents>
          <orderEvent>SOME_EVENT</orderEvent>
        </orderEvents>
      </expectedVendorPaymentTransactions>
    </Testcase>
EOF

document2 = REXML::Document.new <<EOF 
    <Testcase>
      <rootIdentifier>validVendorPaymentFormat7</rootIdentifier>
      <expectedVendorPaymentTransactions>
        <orderEvents><orderEvent>SOME_EVENT</orderEvent></orderEvents>
      </expectedVendorPaymentTransactions>
    </Testcase>
EOF

puts "1: #{REXML::XPath.match(document, xpath).inspect}"
puts "2: #{REXML::XPath.match(document2, xpath).inspect}"

输出:

irb(main):001:0> load './test/test_rexp.rb'
1: ["\n          ", "\n        "]
2: []
=> true

Jens 的最新版本:

irb(main):009:0> load './test/test_rexp.rb'
1: ", "
2: ", "
=> true

【问题讨论】:

    标签: ruby xpath


    【解决方案1】:

    似乎 Ruby 没有将 normalize-space(...) 中的换行符作为空格处理。如果它包含除空格以外的任何内容,您会感兴趣,因此只需删除所有空格。 translate(...) 可以派上用场。第一个参数是您要匹配的内容,第二个字符串是要匹配的内容,第三个参数是要替换的字符;因为它是空的,所以所有匹配的字符都会被删除。

    translate(., ' &#10;', '')
    

    我可以用 Perl 的 XPath 重现该问题,并通过以下查询解决:

    /expectedVendorPaymentTransactions/orderEvents/node()[not(self::orderEvent) or self::text()[translate(., ' &#10;', '')!='']]
    

    更新:Ruby 似乎无法正确解析 XML 实体,但您可以使用 \n 代替换行符:

    translate(., ' \n', '')
    

    【讨论】:

    • 谢谢詹斯。不幸的是,这对我在 ruby​​ 中不起作用,它仍然给出相同的错误消息。
    • 还有其他空格吗?制表符,回车?到目前为止,我只过滤空格和换行符。
    • 不使用其他空格。我已经更新了一个显示问题的 ruby​​ 文件,代码和输出被逐字复制。
    • 似乎 Ruby 没有正确解析实体,但您可以使用 \n 换行(与 XML 实体相比,我认为它不会更糟......)。我更新了我的答案。顺便说一句,+1 以发布出色的 SSCCE
    • 当您将 translate 函数与谓词结合使用时,这似乎是一个错误。要么您必须解决并从 ruby​​ 中删除 ", " 字符串,要么寻找其他解决方案。 :(
    【解决方案2】:

    从 XPATH 中删除空格处理并使用相当简单的 ruby​​ 解决方法。

    工作代码:

    require 'rexml/document'
    require 'rexml/text'
    
    xpath = "//expectedVendorPaymentTransactions/orderEvents/node()[not(self::orderEvent)]"
    document = REXML::Document.new <<EOF 
        <Testcase>
          <rootIdentifier>validVendorPaymentFormat7</rootIdentifier>
          <expectedVendorPaymentTransactions>
            <orderEvents>
              <orderEvent>Fulfill</orderEvent>
            </orderEvents>
          </expectedVendorPaymentTransactions>
        </Testcase>
    EOF
    
    document2 = REXML::Document.new <<EOF 
        <Testcase>
          <rootIdentifier>validVendorPaymentFormat7</rootIdentifier>
          <expectedVendorPaymentTransactions>
            <orderEvents><orderEvent>Fulfill</orderEvent></orderEvents>
          </expectedVendorPaymentTransactions>
        </Testcase>
    EOF
    
    elements = REXML::XPath.match(document, xpath)
    elements.reject! { |element| 
          element.instance_of?(REXML::Text) and element.value.gsub(/[\n ]/,"") == ''
        }
    puts "1: #{elements.inspect}"
    
    elements2 = REXML::XPath.match(document2, xpath)
    elements2.reject! { |element| 
          element.instance_of?(REXML::Text) and element.value.gsub(/[\n\t ]/,"") == ''
        }
    puts "2: #{elements2.inspect}"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多