我有一个分组查询,会产生一个诊所列表。诊所内有患者。并且患者内有处方。我正在尝试使用MarkupBuilder输出这个结构,但我似乎无法使收容工作。
我得到的是:
<worklist>
<clinics>
<clinic id="1" name="Clinic 1"/>
<patient firstName="John" id="2" lastName="Doe"/>
<prescription id="4">
<prescriptionType/>
<duration/>
<drugName>Tums</drugName>
<route/>
<refills>0</refills>
</prescription>
<clinic id="2" name="Clinic 2"/>
<patient firstName="John" id="2" lastName="Doe"/>
<prescription id="2">
<prescriptionType>Formulary</prescriptionType>
<duration>duration</duration>
<drugName>Lipitor</drugName>
<route>route</route>
<refills>5</refills>
</prescription>
<patient firstName="Sylvia" id="4" lastName="Plath"/>
<prescription id="5">
<prescriptionType/>
<duration/>
<drugName>BandAids</drugName>
<route/>
<refills>0</refills>
</prescription>
</clinics>
</worklist>
请注意,诊所元素关闭,不包含患者。并且患者元素关闭并且不包含处方。这是不正确的。它应该是这样的:
<worklist>
<clinics>
<clinic id="1" name="Clinic 1">
<patient firstName="John" id="2" lastName="Doe">
<prescription id="4">
<prescriptionType/>
<duration/>
<drugName>Tums</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
</clinic>
<clinic id="2" name="Clinic 2"/>
<patient firstName="John" id="2" lastName="Doe">
<prescription id="2">
<prescriptionType>Formulary</prescriptionType>
<duration>duration</duration>
<drugName>Lipitor</drugName>
<route>route</route>
<refills>5</refills>
</prescription>
</patient>
<patient firstName="Sylvia" id="4" lastName="Plath">
<prescription id="5">
<prescriptionType/>
<duration/>
<drugName>BandAids</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
</clinic>
</clinics>
</worklist>
这是我的代码:
import groovy.xml.StreamingMarkupBuilder
import groovy.xml.XmlUtil
import javax.ws.rs.GET
import javax.ws.rs.Path
import javax.ws.rs.Produces
@Path('/api/worklist')
class WorklistResource {
def addClinic = { idx, name ->
clinic(id:idx, name:name)
}
def addPatient = { idx, fname, lname ->
patient(id:idx, firstName:fname, lastName:lname)
}
@GET
@Produces(['application/xml','application/json'])
String getWorklistRepresentation() {
def groupedScripts = Prescription.createCriteria().list {
createAlias('clinic', 'clinicAlias')
createAlias('patient', 'patientAlias')
projections {
groupProperty "id"
groupProperty "clinicAlias.id"
groupProperty "patientAlias.id"
}
order "clinicAlias.name"
order "patientAlias.lastName"
order "patientAlias.firstName"
}
def curClinic = null
def curPatient = null
def worklist = new StreamingMarkupBuilder().bind {
worklist {
clinics {
groupedScripts.each { arr ->
def (rx, clinic, patient) = arr
def script = Prescription.get(rx)
def cl = Clinic.get(clinic)
def pat = Patient.get(patient)
if( curClinic != cl ) {
curClinic = cl
addClinic.delegate = delegate
addClinic(cl.id, cl.name)
}
if( curPatient != pat ) {
curPatient = pat
addPatient.delegate = delegate
addPatient(pat.id, pat.firstName, pat.lastName)
}
prescription(id:script.id) {
prescriptionType(script.prescriptionType)
duration(script.duration)
drugName(script.drugName)
route(script.route)
refills(script.refills)
}
}
}
}
}
def xml = XmlUtil.serialize(worklist)
xml
}
}
显然,我需要以某种方式保持诊所关闭,直到我到新诊所或到达收集结束。患者关闭也一样。我只是不确定该怎么做。
提前感谢您的帮助。我需要今晚让这个工作。
答案 0 :(得分:2)
您只能在列表中使用each
方法。您必须注意以下事项:builder.bind
内的每个匹配方法调用都将调用相应的方法/变量;因此你需要不同的名字。这甚至更好,因为你没有做出模棱两可的命名。您可以在eachs
内构建整个XML。它有点大,但这会以你想要的方式填充你的XML:
<强>更新强>
由于你的模型是颠倒的,我做了以下几点:
// definition of the model and mock data
@Canonical class Prescription {
int id
String prescriptionType, duration, drugName, route
int refills
Clinic clinic
Patient patient
}
@Canonical class Clinic {
int id
String name
}
@Canonical class Patient {
int id
String firstName, lastName
}
def patient2 = new Patient(2, "John", "Doe")
def patient4 = new Patient(4, "Sylvia", "Plath")
def clinic1 = new Clinic(1, "Clinic 1")
def clinic2 = new Clinic(2, "Clinic 2")
def prescriptions = [
new Prescription(2, "Formulary", "duration", "Lipitor", "route", 5, clinic1, patient2),
new Prescription(4, null, null, "Tums", null, 0, clinic2, patient2),
new Prescription(5, null, null, "BandAids", null, 5, clinic2, patient4)
]
最好的办法是反转模型,使其与XML结构相匹配。您可以使用此代码段轻松撤消它:
clins = prescriptions.inject([:].withDefault({ [:] })) { map, pres ->
map[ pres.clinic ] << [ (pres.patient) : pres ]
map
}
现在根据地图结构构建XML:
builder = new groovy.xml.StreamingMarkupBuilder()
xml = builder.bind {
clinics {
clins.each { cliEntry -> cli = cliEntry.key
clinic(id: cli.id, name: cli.name) {
cliEntry.value.each { patEntry -> pat = patEntry.key
patient(id: pat.id, firstName: pat.firstName, lastName: pat.lastName){
patEntry.value.each { pres ->
prescription(id: pres.id) {
prescriptionType pres.prescriptionType
duration pres.duration
drugName pres.drugName
route pres.route
refills pres.refills
}
}
}
}
}
}
}
}
测试:
assert xml.toString() == """<clinics><clinic id='1' name='Clinic 1'><patient id='2' firstName='John' lastName='Doe'><prescription id='2'><prescriptionType>Formulary</prescriptionType><duration>duration</duration><drugName>Lipitor</drugName><route>route</route><refills>5</refills></prescription></patient></clinic><clinic id='2' name='Clinic 2'><patient id='2' firstName='John' lastName='Doe'><prescription id='4'><prescriptionType/><duration/><drugName>Tums</drugName><route/><refills>0</refills></prescription></patient><patient id='4' firstName='Sylvia' lastName='Plath'><prescription id='4'><prescriptionType/><duration/><drugName>Tums</drugName><route/><refills>0</refills></prescription></patient></clinic></clinics>"""
答案 1 :(得分:0)
我在这里有一些丑陋的全局_index变量,终止条件和try..catch废话,但我已经在这里工作了好几个小时,这段代码有效:
import groovy.xml.StreamingMarkupBuilder
import groovy.xml.XmlUtil
import javax.ws.rs.GET
import javax.ws.rs.Path
import javax.ws.rs.Produces
@Path('/api/worklist')
class WorklistResource {
def _index = null // global index into groupedScripts collection
def addClinic = { scripts, index ->
addPatient.delegate = delegate
def (rxId, clinicId, patientId) = scripts[index]
def startingClinicId = clinicId
def cl = Clinic.get(clinicId)
clinic(id:cl.id, name:cl.name) {
while( clinicId == startingClinicId ) {
_index = index
index = addPatient(scripts, index)
if( index == -1 ) return -1
try {
(rxId, clinicId, patientId) = scripts[++index]
} catch(NullPointerException e) {
return -1
}
}
}
return _index
}
def addPatient = { scripts, index ->
def result = index
def (rxId, clinicId, patientId) = scripts[index]
def startingPatientId = patientId
def pat = Patient.get(patientId)
patient(id:pat.id, firstName:pat.firstName, lastName:pat.lastName) {
while( patientId == startingPatientId ) {
_index = index
def script = Prescription.get(rxId)
prescription(id:script.id) {
prescriptionType(script.prescriptionType)
duration(script.duration)
drugName(script.drugName)
route(script.route)
refills(script.refills)
}
try {
(rxId, clinicId, patientId) = scripts[++index]
} catch(NullPointerException e) {
return -1
}
}
}
return _index
}
@GET
@Produces(['application/xml','application/json'])
String getWorklistRepresentation() {
def groupedScripts = Prescription.createCriteria().list {
createAlias('clinic', 'clinicAlias')
createAlias('patient', 'patientAlias')
projections {
groupProperty "id"
groupProperty "clinicAlias.id"
groupProperty "patientAlias.id"
}
order "clinicAlias.name"
order "patientAlias.lastName"
order "patientAlias.firstName"
}
def finished = false
def worklist = new StreamingMarkupBuilder().bind {
worklist {
clinics {
_index = 0
addClinic.delegate = delegate
while( !finished && _index < groupedScripts.size() ) {
_index = addClinic(groupedScripts, _index)
if( _index == -1 ) finished = true
++_index
}
}
}
}
def xml = XmlUtil.serialize(worklist)
xml
}
}
输出结果为:
<worklist>
<clinics>
<clinic id="1" name="Clinic 1">
<patient firstName="Mariah" id="3" lastName="Brookstone">
<prescription id="1">
<prescriptionType>New</prescriptionType>
<duration>30 days</duration>
<drugName>Lisinopril 20mg Tablet</drugName>
<route>By Mouth</route>
<refills>2</refills>
</prescription>
</patient>
<patient firstName="John" id="2" lastName="Doe">
<prescription id="4">
<prescriptionType/>
<duration/>
<drugName>Tums</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
</clinic>
<clinic id="2" name="Clinic 2">
<patient firstName="Mariah" id="3" lastName="Brookstone">
<prescription id="11">
<prescriptionType/>
<duration/>
<drugName>Milk Duds</drugName>
<route/>
<refills>0</refills>
</prescription>
<prescription id="12">
<prescriptionType/>
<duration/>
<drugName>Hershey</drugName>
<route/>
<refills>0</refills>
</prescription>
<prescription id="7">
<prescriptionType/>
<duration/>
<drugName>Skittles</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
<patient firstName="John" id="2" lastName="Doe">
<prescription id="2">
<prescriptionType>Formulary</prescriptionType>
<duration>duration</duration>
<drugName>Lipitor</drugName>
<route>route</route>
<refills>5</refills>
</prescription>
</patient>
<patient firstName="Sylvia" id="4" lastName="Plath">
<prescription id="5">
<prescriptionType/>
<duration/>
<drugName>BandAids</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
</clinic>
<clinic id="3" name="Clinic 3">
<patient firstName="Jane" id="12" lastName="Doe">
<prescription id="9">
<prescriptionType/>
<duration/>
<drugName>Reese's Pieces</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
<patient firstName="Jill" id="13" lastName="Doe">
<prescription id="8">
<prescriptionType/>
<duration/>
<drugName>Toothpaste</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
<patient firstName="Jim" id="11" lastName="Doe">
<prescription id="10">
<prescriptionType/>
<duration/>
<drugName>Hallmark</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
<patient firstName="John" id="2" lastName="Doe">
<prescription id="6">
<prescriptionType/>
<duration/>
<drugName>Gauze</drugName>
<route/>
<refills>0</refills>
</prescription>
</patient>
</clinic>
</clinics>
</worklist>
那(几乎)正是我所追求的。