XQuery for loop дает повторяющиеся результаты

Я использую XQuery для анализа двух наборов результатов тестов, имеющих одинаковую структуру XML. Функция ниже создает новый набор элементов, которые являются отдельными сравнениями тестовых примеров двух наборов результатов. Для каждого тестового примера должно быть отношение 1-1 для двух наборов, но мой код иногда производит 8 сравнений, и я не могу понять, почему!

Вот мой входной XML, используемый для обоих наборов с разными данными (например, сокращенно):

 <tests>
  <test-group name="TestA">
    <test-case name="CaseA1" success="true"/>
    <test-case name="CaseA2" success="false"/>
    <test-case name="CaseA3" success="true"/>
  </test-group>
  <test-group name="TestB">
    <test-case name="CaseB1" success="false"/>
    <test-case name="CaseB2" success="false"/>
    <test-case name="CaseB3" success="true"/>
  </test-group>
  <test-group name="TestC">
    <test-case name="CaseC1" success="false"/>
    <test-case name="CaseC2" success="false"/>
    <test-case name="CaseC3" success="true"/>
  </test-group>
</tests>

Пример вывода:

 <test-state delta1="15" delta2="false" isPass="true" fixture="TestA" case="CaseA1"/>
 <test-state delta1="12" delta2="true" isPass="false" fixture="TestA" case="CaseA1"/>
 <test-state delta1="5" delta2="false" isPass="true" fixture="TestA" case="CaseA1"/>
 <test-state delta1="15" delta2="false" isPass="true" fixture="TestC" case="CaseC1"/>
 <test-state delta1="12" delta2="true" isPass="false" fixture="TestC" case="CaseC1"/>
 <test-state delta1="5" delta2="false" isPass="true" fixture="TestC" case="CaseC1"/>

Вот мой Xquery (например, модифицированный):

declare function app:runReport() {
    let $new-run := collection('collection1')
    let $old-run := collection('collection2')    
    return 
<report> 
    {         
    for $new-case in $new-run//test-case,
        $old-case in $old-run//test-case
        where $new-case/@name = $old-case/@name and $new-case/../@name = $old-case/../@name
            return
                let $new-msg := xs:string($new-case/message)
                let $old-msg := xs:string($old-case/message)
                let $new-len := string-length($new-msg)
                let $old-len := string-length($old-msg)
                let $msg-dif := $new-len - $old-len

                let $delta1 := fn:compare(xs:string($new-case/@success),xs:string($old-case/@success)) = 0
                let $delta2 := abs($msg-dif)
                return        
                   <test-state 
                          delta1="{$delta1}"
                          delta2="{$delta2}"
                          isPass="{$new-case/@success}"
                         fixture="{$new-case/../@name}"
                            case="{$new-case/@name}"
                            path="unknownPath"/>
    }        
</report>
};

Мне кажется, что он производит перестановки каждой комбинации между $ new-case и $ old-case, но я понятия не имею, почему. Я бы попытался отфильтровать дубликаты, но они не являются точными дубликатами, иногда кажется, что вместо $ new-case используется $ old-case.


person 0tombo0    schedule 11.09.2013    source источник


Ответы (2)


Мне кажется, что он делает перестановки каждой комбинации между $ new-case и $ old-case

Именно это и происходит благодаря структуре вашего for. Например:

for $x in (1, 2, 3), $y in ('a', 'b', 'c')
return <z>{$x, $y}</z>

=>

<z>1 a</z>
<z>1 b</z>
<z>1 c</z>
<z>2 a</z>
<z>2 b</z>
<z>2 c</z>
<z>3 a</z>
<z>3 b</z>
<z>3 c</z>

Вместо этого вы можете просто найти соответствующий старый тест:

for $new-case in $new-run//test-case
let $old-case := $old-run//test-case[@name = $new-case/@name]
return
...
person wst    schedule 11.09.2013
comment
Я согласен, что это должно сработать, но я пробовал это, и это уменьшает количество дополнительных сравнений тестовых состояний с 8 до 3, а в некоторых местах только 2, так что это лучше, но все еще не используется. Это похоже на довольно стандартный тип запроса, так что еще я мог упустить? Спасибо за помощь. - person 0tombo0; 12.09.2013
comment
@ThomasKefauver Вне всяких сомнений, я бы сказал, сначала дважды проверьте, что в обоих наборах данных точно одинаковое количество test-case, и что @name также всегда уникален в обоих. В противном случае вам, вероятно, следует опубликовать сокращенный набор тестовых данных, демонстрирующих вашу проблему, чтобы я мог воспроизвести его. - person wst; 12.09.2013

Можно предположить, что два ваших ввода отличаются от образца, который вы нам показали, способами, которые влияют на решающее сравнение $new-case/@name = $old-case/@name and $new-case/../@name = $old-case/../@name - либо в новой коллекции, либо в старой, либо в обеих комбинациях ../@name и ./@name не уникален.

Чтобы найти дубликаты в данных, я бы запустил запрос примерно так:

let $new-run := collection('collection1'),
    $old-run := collection('collection2')    
for $name in distinct-values(
        for $tc in ($new-run | $old-run)//test-case/@name
        return concat($tc/../@name,' || ',$tc/@name) 
    )
let $old := $old-run//test-case
            [concat(../@name,' || ', @name) = $name],
    $new := $new-run//test-case
            [concat(../@name,' || ', @name) = $name]
where count($old) gt 1 
   or count($new) gt 1
return <duplicate-id name="{$name}"
                     old-count="{count($old)}"
                     new-count="{count($new)}"/>
person C. M. Sperberg-McQueen    schedule 16.09.2013
comment
Да, входные данные представляют собой более крупную XML-структуру, но никакая пара имя-тест-группы / имя-тест-кейса определенно не является уникальной комбинацией, имеющей уникальный аналог в другом наборе. Я полностью озадачен этим. Я потратил больше недели, копаясь в Google и пробуя альтернативные методы выполнения этого запроса, но я в растерянности :( Ради своего здравого смысла я собираюсь обвинить его в том, что XQuery «глючит». - person 0tombo0; 27.09.2013
comment
Конечно, возможно, что ваша реализация XQuery содержит ошибки. Однако, по моему опыту, более вероятно, что в ваших данных есть грязь. Вы действительно проверяли наличие повторяющихся значений @name? - person C. M. Sperberg-McQueen; 28.09.2013