2012-07-09 50 views
5

tôi có mã này:Groovy MarkupBuilder tên xung đột

String buildCatalog(Catalog catalog) { 
    def writer = new StringWriter() 
    def xml = new MarkupBuilder(writer) 
    xml.catalog(xmlns:'http://www.sybrium.com/XMLSchema/NodeCatalog') { 
     'identity'() { 
      groupId(catalog.groupId) 
      artifactId(catalog.artifactId) 
      version(catalog.version) 
     } 
    } 

    return writer.toString(); 
} 

Nó tạo xml này:

<catalog xmlns='http://www.sybrium.com/XMLSchema/NodeCatalog'> 
    <groupId>sample.group</groupId> 
    <artifactId>sample-artifact</artifactId> 
    <version>1.0.0</version> 
</catalog> 

Chú ý rằng "bản sắc" tag là mất tích ... Tôi đã thử tất cả mọi thứ trong thế giới để có được nút đó xuất hiện. Tôi đang tách tóc ra!

Xin cảm ơn trước.

Trả lời

11

Có thể có một cách tốt hơn, nhưng một Bí quyết là để gọi invokeMethod trực tiếp:

String buildCatalog(Catalog catalog) { 
    def writer = new StringWriter() 
    def xml = new MarkupBuilder(writer) 
    xml.catalog(xmlns:'http://www.sybrium.com/XMLSchema/NodeCatalog') { 
     delegate.invokeMethod('identity', [{ 
      groupId(catalog.groupId) 
      artifactId(catalog.artifactId) 
      version(catalog.version) 
     }]) 
    } 

    return writer.toString(); 
} 

Đây là một cách hiệu quả những gì Groovy đang làm đằng sau hậu trường. Tôi không thể nhận được delegate.identity hoặc owner.identity để hoạt động, đó là các thủ thuật thông thường.


Chỉnh sửa: Tôi đã tìm hiểu điều gì đang xảy ra.

Groovy adds a method có chữ ký identity(Closure c) cho mọi đối tượng.

Điều này có nghĩa là khi bạn cố gắng tự động gọi phần tử identity trên trình tạo XML, trong khi truyền trong một đối số đóng, nó gọi phương thức identity(), giống như gọi số delegate({...}) ở bên ngoài.

Sử dụng invokeMethod các lực lừa để Groovy bỏ qua Giao thức đối tượng meta và coi phương thức là phương pháp động, mặc dù phương thức identity đã tồn tại trên MetaObject.

Biết điều này, chúng tôi có thể tập hợp một giải pháp tốt hơn, dễ đọc hơn. Tất cả chúng ta phải làm là thay đổi chữ ký của phương pháp này, như vậy:

String buildCatalog(Catalog catalog) { 
    def writer = new StringWriter() 
    def xml = new MarkupBuilder(writer) 
    xml.catalog(xmlns:'http://www.sybrium.com/XMLSchema/NodeCatalog') { 
     // NOTE: LEAVE the empty map here to prevent calling the identity method! 
     identity([:]) { 
      groupId(catalog.groupId) 
      artifactId(catalog.artifactId) 
      version(catalog.version) 
     } 
    } 

    return writer.toString(); 
} 

Đây là nhiều hơn nữa có thể đọc được, nó rõ ràng hơn mục đích, và những nhận xét nên (hy vọng) ngăn chặn bất cứ ai từ loại bỏ các "không cần thiết" trống rỗng bản đồ.

+0

Điều đó có hiệu quả, nhưng bạn có thể giải thích điều này không? Đại biểu là gì và tại sao delegate.identity khác với delegate.invokeMethod ('Identity')? –

+0

Tôi đã tìm ra, tôi sẽ cập nhật câu trả lời của mình. – OverZealous

+0

FYI: Tôi đã theo dõi điều này bằng cách sử dụng GroovyConsole để kiểm tra đối tượng XML. Điều này cho tôi biết rằng phương thức 'identity' đã tồn tại với một' Closure' duy nhất làm đối số của nó. – OverZealous

Các vấn đề liên quan