1
votes

During migration site from CQ5.4 to AEM6 I've faced problem in importing XML data to JCR.

On CQ5.4 we used "Content Loader Tool"(http(s)://[host]:[port]/crx/loader/index.jsp ) to load xml to jcr. Starting from CQ5.6.1 that tool was deprecated and gone. AEM6 doesn't have it also, the same like several crx:Xml* primary node types(crx:XmlCharacterData, crx:XmlDocument, crx:XmlElement, crx:XmlNode).

I've tried to re-import data programmatically, below sample groovy script

importXML();
def importXML(){
    FileInputStream  inputStream = new FileInputStream("c:/data.xml "); // XML file
    session.importXML("/content/xmlNode", // Destination JCR node
        inputStream ,
        javax.jcr.ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW);
    session.save();
}

But as import result, I lost all sibling data. Imported data has only one node on each layer in JCR. The reason is Oak doesn't support Same Name Siblings (SNS).

http://docs.adobe.com/docs/en/aem/6-0/deploy/upgrade/introduction-to-oak.html http://jackrabbit.apache.org/oak/docs/differences.html#Same_name_siblings

I don't need support SNS or crx:Xml* node types. I'm happy to have unique generated names for siblings(i.e. node_1, node_2) and primary node type "nt:unstructured". Or any other jcr structure, that keeps all imported data from XML.

How to import XML data to AEM6? Help me out, please.

2

2 Answers

1
votes

Hopefully this will help someone

here is how I've done it using Importer:

1)here is a simple importer class

@Service(value = Importer.class)
@Component
@Property(name = "importer.scheme", value = "importedData", propertyPrivate =true)

public class DataImporter implements Importer {
private final String SOURCE_URL = "http://someserver/data.xml";
private static final Logger LOGGER = LoggerFactory.getLogger(DealerDataImporter.class);

@Override
public void importData(String s, String s2, Resource resource) throws ImportException {

    try {

        URL url = new URL(SOURCE_URL);
        URLConnection connection = url.openConnection();
        Document doc = parseXML(connection.getInputStream());
        NodeList Nodes = doc.getElementsByTagName("retailer");
        for (int i = 0; i < Nodes.getLength(); i++) {
            Element element = (Element) Nodes.item(i);
            String id = element.getElementsByTagName("id").item(0).getTextContent();
            String name = element.getElementsByTagName("display_name").item(0).getTextContent();
            String about = element.getElementsByTagName("about").item(0).getTextContent();
            writeToRepository(id, name, about, resource);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private void writeToRepository(String id, String name, String about, Resource resource) {

    try {
        javax.jcr.Node parentNode = resource.adaptTo(javax.jcr.Node.class);

        //Say we want this to be a Page node (use NameConstants.NT_PAGE = cq:Page)
        //all of node types can be created this way
        javax.jcr.Node pageNode = JcrUtil.createPath(parentNode.getPath() + "/" + name, NameConstants.NT_PAGE, parentNode.getSession());
        //Page nodes need jcr:content node to hold all teh relevant properties (NameConstants.NN_CONTENT = "jcr:content")
        javax.jcr.Node contentNode = JcrUtil.createPath(pageNode.getPath() + "/" + NameConstants.NN_CONTENT, "cq:PageContent", parentNode.getSession());
        //set some properties
        contentNode.setProperty("about", about);
        contentNode.setProperty("id", id);
        //save session
        parentNode.getSession().save();

    } catch (Exception e1) {
        e1.printStackTrace();
    } 
}
private Document parseXML(InputStream stream){...}
}

2)Then in CRXde under /etc/importers/polling add new node of type sling:Folder and add some properties:

a) target [String] this is a path to a repository resource this resource will be parsed to your Importer Class.

b) source [String] this is if you're looking to import from multiple xml files IMPORTANT the value needs to start importedData (as a property in the class that is where they link) followed by :SOME_VALIABLE this is a s2 varaible in the above example.

c) interval[Long] how often to run Importer

d) add an mixin jcr:mixinTypes type cq:PollConfig

This should be it and so far I was able to import any data using this techniques

0
votes

Unfortunately it looks like the ability to automatically create unique nodes does not exist (JcrUtils for example has the createUnique method that will append numbers to conflicting node names). It would be possible to use XSLT to rename each node so that it is unique.