Groovy XMLSlurper обновить документ в соответствии со схемой - PullRequest
0 голосов
/ 10 августа 2011

У меня возникла проблема, которую я, кажется, не могу преодолеть, и надеюсь, что некоторые из вас, знающих женщин, смогут найти решение.

У меня есть документ с XSD, содержащий последовательность. Как известно, это означает, что все элементы должны появляться в указанном порядке. Мне нужно использовать это, потому что некоторые из них также являются необязательными (minOccurs = "0").

Вот упрощенная часть схемы:

    <xs:element name="result">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="tns:resultCode"/>
            <xs:element ref="tns:resultAbbreviations" minOccurs="0"/>
            <xs:element ref="tns:resultReporter" minOccurs="0"/>
            <xs:element ref="tns:vendorData" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>

Связанная часть документа XML:

<lab:order>
  <lab:results>
     <lab:result>
        <lab:resultCode>005009</lab:resultCode>
        <lab:resultAbbreviations>
           <lab:resultAbbreviation>FOO</lab:resultAbbreviation>
        </lab:resultAbbreviations>
        <lab:resultReporter>
           <lab:enteredEmployeeId>86118</lab:enteredEmployeeId>
        </lab:resultReporter>
        <lab:vendorData value="123" key="ABC"/>
        <lab:vendorData value="ABC" key="123"/>
     </lab:result>
     <lab:result>
        <lab:resultCode>005025</lab:resultCode>
     </lab:result>
     ...

Мне нужно уметь делать две вещи:

  1. Если элемент существует, обновите его значение. Например. измените значение inputEmployeeId на «EntVal» для resultCode «005009». Для этого необходимо найти, существует ли этот элемент.
  2. Если элемент не существует, добавьте его в место, которое пройдет проверку в соответствии со схемой. Например. добавьте resultReporter и введитеEmployeeId для resultCode "005025". Обратите внимание, что существуют дополнительные элементы, которые могут присутствовать или не присутствовать, как показано в приведенном выше фрагменте XML.

Мне удалось добавить узел в конец «результирующего» узла, но я не могу найти найти работу для обновления или вставить узел в нужное место, чтобы удовлетворить XSD. Вот код:

    ...
//-- ResultReporter: enteredEmployeeId, verifiedEmployeeId
// Must add to proper result, based on code
ResultReporter reporter = nextResult.getReporter();
NodeChild codeNode = getResultNodeFor( nextResult.getCode() );
if( codeNode != null ) {    //found proper result - does reporter exist already?
    def reporterNode = codeNode.find { it.name() == 'resultReporter' }
    if( !reporterNode.isEmpty() ) { //reporter node exists - update it
        reporterNode.'lab:enteredEmployeeId'( nextResult.getReporter().getEnteredEmployeeId() )
    } else {    //element does not exist - add new one
        codeNode.appendNode {
            'lab:resultReporter' {
                'lab:enteredEmployeeId'(nextResult.getReporter().getEnteredEmployeeId())
            }
        }
    }
} else {    //not found
    throw new IllegalArgumentException("Cannot add reporter for nonexistent result code: " + nextResult.getCode() );
}
...
    /**
 * @param aCode
 * @return the Node with resultCode = aCode, else null
 */
private NodeChild getResultNodeFor( String aCode ) {
    for( def nextResult : labDoc.order.results.children() ) {
        if(  nextResult.resultCode.text().equals(aCode) ) { //found
            return nextResult;
        }
    }
    return null;    //not found
}

Я ищу такой вывод в формате XML (обратите внимание, что значение первого результата обновлено, второе вставлено - но в нужном месте ... там могут быть и другие элементы!):

   <lab:order>
  <lab:results>
     <lab:result>
        <lab:resultCode>005009</lab:resultCode>
        <lab:resultAbbreviations>
           <lab:resultAbbreviation>FOO</lab:resultAbbreviation>
        </lab:resultAbbreviations>
        <lab:resultReporter>
           <lab:enteredEmployeeId>EntVal</lab:enteredEmployeeId>
        </lab:resultReporter>
        <lab:vendorData value="123" key="ABC"/>
        <lab:vendorData value="ABC" key="123"/>
     </lab:result>
     <lab:result>
        <lab:resultCode>005025</lab:resultCode>
        <lab:resultReporter>
           <lab:enteredEmployeeId>EntVal</lab:enteredEmployeeId>
        </lab:resultReporter>
     </lab:result>
     ...

Итак: кто-нибудь может сказать мне, как заставить это работать? Спасибо! Mark

1 Ответ

0 голосов
/ 11 августа 2011

ОК, прогресс. К счастью, у меня есть контроль над схемой, поэтому я изменил «последовательность» на «все». «all» позволяет «minOccurs» 0 или 1, так что я могу обрабатывать необязательно таким образом. Я реорганизовал один элемент, который может встречаться несколько раз, чтобы он стал дополнительным элементом, содержащим элементы, которые могут повторяться.

Поскольку «все» разрешает любой заказ (и необязательный), я могу добавлять где угодно, например, добавляя в конец.

Что касается нахождения существующего, это работает:

codeNode.children().find { it.name() == "resultReporter" }

Я проверяю «isEmpty ()» на результат этого кода, чтобы увидеть, действительно ли он существует.

Итак: не общее решение (например, если я не могу изменить XSD), но работает для того, что мне нужно. Надеюсь, что это помогает другим.

Если кто-то знает, как решить это вообще, пожалуйста, говорите!

Чтобы дать полное решение, вот код, который работает для изменения XML:

    def reporterNode = codeNode.children().find { it.name() == "resultReporter" }
if( !reporterNode.isEmpty() ) { //reporter node exists - update it
    reporterNode.replaceNode { node ->
        'lab:resultReporter'() {
            'lab:enteredEmployeeId'(nextResult.getReporter().getEnteredEmployeeId())
        }
    }
} else {    //element does not exist - add new one
    codeNode.appendNode {
        'lab:resultReporter' {
            'lab:enteredEmployeeId'(nextResult.getReporter().getEnteredEmployeeId())
        }
    }
}
...