2

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?

2 Answers 2

2

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,

Sign up to request clarification or add additional context in comments.

6 Comments

The problem here is, I extract the data from multiple xpaths of an xml. So i can not directly map pojo to an xml. and i donot see any examples in those links where i can convert ExtractedResult object to POJO or extracting result response and converting to POJO
One alternative to using extract would be to use JAXB to serialize your POJO to discover what XML JAXB can take as input. Then, write a transform from the source document to the JAXB input XML and install it on the server. On the client, you can then use JAXBHandle to read multiple documents for a query, transforming the documents on the server.
To detail my scenario little more .. I have a source XML which gets persisted by one of the background processes. Now i need to retrieve some element values with XPath translations from Source, Say i extract 5 values of 20 elements in the sourceXML and show it in the UI. Later if business asks to add one more field to the extraction and make 6 values to be displayed in the UI, i would need to add that. My understanding is that the above solution, will not be scalable for this scenario. If I am missing something, would be really helpful, if you can detail out the design approach i should take.
The server-side transform would scale. It is slightly less agile, in that you would have to reinstall the transform after each change. Another alternative would be to do a bulk read on the documents and do the projection on the client side. But, the HTTP transfer would be passing more data. On the other hand, if you are showing the values in a UI, you might consider consuming them directly instead of assigning them to a POJO first. Anyway, I hope that gives you a sense of the alternatives available to you.
Okie, the choices seem to be limited.any references to load the serverside transform
|
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.