venkata
venkata

Reputation: 51

Iterating results using MarkLogic java client api

I have an XML, with multiple nodes

Have written query options with a parameter and save it to database

<search:options xmlns:search="http://marklogic.com/appservices/search">
  <search:constraint name="extValue">
        <search:value>
            <search:element ns="urn:hl7-org:v2xml"  name="CX.1" />
        </search:value>
  </search:constraint>
  <search:extract-document-data xmlns="urn:hl7-org:v2xml"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xsi:schemaLocation="urn:hl7-org:v2xml ADT_A01.xsd">
      <search:extract-path>/ADT_A01/PID/PID.3/CX.4/HD.1</search:extract-path>
      <search:extract-path>/ADT_A01/PV1/PV1.7/XCN.2/FN.1</search:extract-path>
      <search:extract-path>/ADT_A01/PV1/PV1.7/XCN.3</search:extract-path>
      <search:extract-path>/ADT_A01/PV1/PV1.4/CWE.1</search:extract-path>
      </search:extract-document-data>
  </search:options>

retrieved results

DatabaseClient client = factory.getSuperMLConnection();
QueryManager queryMgr = client.newQueryManager();
//used the query options above which is saved to DB with name v2searchQueryOpts
StructuredQueryBuilder qb = new StructuredQueryBuilder("v2searchQueryOpts");
//this is one of the element value in the xml
StructuredQueryDefinition querydef = 
        qb.and(qb.valueConstraint("extValue", "1.32022.1.10.2"));
SearchHandle resultsHandle = queryMgr.search(querydef, new SearchHandle());
MatchDocumentSummary[] summaries = resultsHandle.getMatchResults();
// here is where i am concerned.
for (MatchDocumentSummary summary : summaries) {
    ExtractedResult extracted = summary.getExtracted();
    if (Format.XML == summary.getFormat()) {
        Document facility = extracted.next().getAs(Document.class);
        Document status = extracted.next().getAs(Document.class);
        Document physicianFirstName = extracted.next().getAs(Document.class);
        Document physicianLastName = extracted.next().getAs(Document.class);
        System.out.println("status is :: " + status.getFirstChild().getTextContent());
        System.out.println("facility is :: " + facility.getFirstChild().getTextContent());
        System.out.println("physicianFirstName is :: " + physicianFirstName.getFirstChild().getTextContent());
        System.out.println("physicianLastName is :: " + physicianLastName.getFirstChild().getTextContent());
    }
    }
}

The result from the database has extracted content as below

<search:extracted>
    <HD.1 xmlns="urn:hl7-org:v2xml">ABC</HD.1>
    <CWE.1 xmlns="urn:hl7-org:v2xml">E</CWE.1>
    <FN.1 xmlns="urn:hl7-org:v2xml">Sri</FN.1>
    <XCN.3 xmlns="urn:hl7-org:v2xml">N</XCN.3>
</search:extracted>

My objective is to retrieve and populate a java POJO. is there any other way i can directly map my result to POJO?

Upvotes: 2

Views: 423

Answers (2)

Sam Mefford
Sam Mefford

Reputation: 2475

For my answer I'm assuming you want to leave the persisted documents as-is. I believe you have two choices to retrieve those directly to a POJO:

  1. transform the results to XML appropriate for JAXBHandle or JSON appropriate for JacksonDatabindHandle
  2. use selected="include-with-ancestors" and model your POJO's to fit your XML structure

The first approach requires installing a REST transform which is demonstrated in SearchResponseTransform.java. I'm demonstrating here the second approach. For the sake of example I've simplified your XML. I'll leave it as an exercise for you to either use your JAXB ninja skills to configure POJO's that map to your XML or use the technique from SearchResponseTransform.java to transform the results to something simple like this example.

Here is the XML I'll insert into the db. It's based on yours, but simplified:

<ADT_A01 xmlns='urn:hl7-org:v2xml'>
    <CX.1>1.32022.1.10.2</CX.1>
    <HD.1>ABC</HD.1>
    <FN.1>Sri</FN.1>
    <XCN.3>N</XCN.3>
    <CWE.1>E</CWE.1>
</ADT_A01>

The search options I'll use are almost the same as yours except I simplified the paths to match the sample XML and I added selected="include-with-ancestors" which is the key to get one XML structure containing all the extracted items. Using this, I get back this in the results:

<search:extracted kind="element">
    <ADT_A01 xmlns="urn:hl7-org:v2xml">
        <HD.1>ABC</HD.1><FN.1>Sri</FN.1><XCN.3>N</XCN.3><CWE.1>E</CWE.1>
    </ADT_A01>
</search:extracted>

Here's the target POJO (save as ADT_A01.java): import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlElement;

@XmlRootElement(name="ADT_A01", namespace="urn:hl7-org:v2xml")
public class ADT_A01 {
    @XmlElement(name="HD.1")
    public String HD_1;
    @XmlElement(name="FN.1")
    public String FN_1;
    @XmlElement(name="XCN.3")
    public String XCN_3;
    @XmlElement(name="CWE.1")
    public String CWE_1;

    public String toString() {
        return "HD_1=[" + HD_1 + "] FN_1=[" + FN_1 + "] XCN_3=[" +
            XCN_3 + "] CWE_1=[" + CWE_1 + "]";
    }
}

And here's the rest of the code (save as JAXBExtract.java)

import com.marklogic.client.DatabaseClient;
import com.marklogic.client.DatabaseClientFactory;
import static com.marklogic.client.DatabaseClientFactory.Authentication.DIGEST;
import com.marklogic.client.document.XMLDocumentManager;
import com.marklogic.client.query.QueryManager;
import com.marklogic.client.query.StructuredQueryBuilder;
import com.marklogic.client.query.StructuredQueryDefinition;
import com.marklogic.client.query.RawCombinedQueryDefinition;
import com.marklogic.client.query.MatchDocumentSummary;
import com.marklogic.client.query.ExtractedItem;
import com.marklogic.client.query.ExtractedResult;
import com.marklogic.client.io.SearchHandle;
import com.marklogic.client.io.StringHandle;
import com.marklogic.client.io.Format;
import com.marklogic.client.io.JAXBHandle;
import javax.xml.bind.JAXBContext;

public class JAXBExtract {
    private static DatabaseClient client = DatabaseClientFactory.newClient(
        "localhost", 8000, "admin", "admin", DIGEST);
    private static XMLDocumentManager docMgr =
        client.newXMLDocumentManager();

    public static void main(String[] args) throws Exception {
        String xml =
            "<ADT_A01 xmlns='urn:hl7-org:v2xml'>" +
                "<CX.1>1.32022.1.10.2</CX.1>" +
                "<HD.1>ABC</HD.1>" +
                "<FN.1>Sri</FN.1>" +
                "<XCN.3>N</XCN.3>" +
                "<CWE.1>E</CWE.1>" +
            "</ADT_A01>";
        String docId = "JAXBTransform_doc1.xml";
        docMgr.writeAs(docId, xml);
        String options =
            "<search:options>" +
                "<search:constraint name='extValue'>" +
                    "<search:value>" +
                        "<search:element ns='urn:hl7-org:v2xml'  name='CX.1' />" +
                    "</search:value>" +
                "</search:constraint>" +
                "<search:extract-document-data selected='include-with-ancestors' " +
                    "xmlns='urn:hl7-org:v2xml'>" +
                    "<search:extract-path>//HD.1</search:extract-path>" +
                    "<search:extract-path>//FN.1</search:extract-path>" +
                    "<search:extract-path>//XCN.3</search:extract-path>" +
                    "<search:extract-path>//CWE.1</search:extract-path>" +
                "</search:extract-document-data>" +
            "</search:options>";
        QueryManager queryMgr = client.newQueryManager();
        StructuredQueryBuilder qb = new StructuredQueryBuilder();
        StructuredQueryDefinition querydef =
                qb.and(qb.valueConstraint("extValue", "1.32022.1.10.2"));
        // normally you'd install your options on the server, I'm just doing
        // RawCombinedQueryDefinition to remove the installation step from my example
        RawCombinedQueryDefinition rawQuery = queryMgr.newRawCombinedQueryDefinition(
            new StringHandle(
                "<search:search xmlns:search='http://marklogic.com/appservices/search'>" +
                    querydef.serialize() +
                    options +
                "</search:search>").withFormat(Format.XML));
        SearchHandle resultsHandle = queryMgr.search(rawQuery, new SearchHandle());
        MatchDocumentSummary[] summaries = resultsHandle.getMatchResults();
        // you only have to register ADT_A01.class if you want to use getAs
        // see http://www.marklogic.com/blog/io-shortcut-marklogic-java-client-api/
        DatabaseClientFactory.getHandleRegistry().register(
            JAXBHandle.newFactory(ADT_A01.class)
        );
        for (MatchDocumentSummary summary : summaries) {
            ExtractedResult extracted = summary.getExtracted();
            if (Format.XML == summary.getFormat()) {
                ExtractedItem item = extracted.next();
                // since I registered ADT_A01.class via JAXBHandle, it is used
                // behind the scenes to marshall the object
                ADT_A01 myObj = item.getAs(ADT_A01.class);
                System.out.println("myObj=[" + myObj + "]");
                System.out.println("extracted xml=[" + item.getAs(String.class) + "]");
            }
        }
        client.newXMLDocumentManager().delete(docId);
    }
}

Upvotes: 1

ehennum
ehennum

Reputation: 7335

The easiest approach is to use the POJO facade introduced in MarkLogic 8:

http://docs.marklogic.com/guide/java/binding

An alternative is to use the JAXBHandle and read multiple documents for a query:

http://docs.marklogic.com/javadoc/client/com/marklogic/client/io/JAXBHandle.html http://docs.marklogic.com/guide/java/bulk#id_37758

Hoping that helps,

Upvotes: 2

Related Questions