Groovy XMLSlurper更新文档以匹配模式

时间:2011-08-10 19:06:28

标签: groovy xsd xmlslurper

我遇到了一个问题,我似乎无法继续前进,并希望你们中的一些知识渊博的专家可以提供解决方案。

我有一个包含序列的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. 如果元素存在,请更新其值。例如。将enteredEmployeeId值更改为resultCode“005009”的“EntVal”。这需要查找该元素是否存在。
  2. 如果元素不存在,请将其添加到将根据模式传递验证的位置。例如。为resultCode“005025”添加resultReporter和enteredEmployeeId。请注意,上面的XML代码段中有可能存在或不存在的可选元素。
  3. 我已经能够在“结果”节点的末尾添加一个节点,但无法使查找工作更新,也无法将节点插入适当的位置以满足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>
         ...
    

    所以:谁能告诉我如何使这项工作?谢谢!标记

1 个答案:

答案 0 :(得分:0)

好的,进步。幸运的是,我可以控制模式,所以我将“序列”更改为“全部”。 “all”允许“minOccurs”为0或1,所以我可以用这种方式处理。我重构了一个可能多次出现的元素,它是一个包含可重复元素的可选元素。

由于“all”允许任何订单(和可选),我可以在任何地方添加,例如追加到最后。

至于寻找现有的,这是有效的:

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())
        }
    }
}