cancel
Showing results for 
Search instead for 
Did you mean: 

Error using XML from Alfresco and freeMarker

pravin
Champ in-the-making
Champ in-the-making
I need help in processing XML from freeMarker. I am posting the XML to alfresco( Community version 2.9B) which is stored in the model and later accessed in FreeMarker. However I am getting the following error 'Expected hash freemarker.template.SimpleScalar'

.js code
var xmlStr = args.xmlData; 
var xmlDoc = new XML(xmlStr);
model.xmlDoc=xmlDoc.toString();  // tried with removing toString(), but the same error

template code
$(xmlDoc.Member}

XML that is posted
<Family><Member>John</Member></Family>

Error
<message>Error during processing of the template 'Expected hash. xmlDoc evaluated instead to freemarker.template.SimpleScalar on line 1, column 3 in test.post.xml.ftl.'. Please contact your system administrator.</message>
  <exception>org.alfresco.service.cmr.repository.TemplateException - Error during processing of the template 'Expected hash. xmlDoc evaluated instead to freemarker.template.SimpleScalar on line 1, column 3 in test.post.xml.ftl.'. Please contact your system administrator.</exception>

Pravin
7 REPLIES 7

mikeh
Star Contributor
Star Contributor
What about xmlDoc.Family.Member? (and without the toString())

Mike

pravin
Champ in-the-making
Champ in-the-making
Mike,

I tired using xmlDoc.Family.Member ( with and without toString()), still getting the same error.

Pravin

kmartino
Champ in-the-making
Champ in-the-making
Hello,

Has there been any solution to this.  I am seeing the same behavior.  And in my use case - I am attempting to parse a working XSD file so I know the XML content is well formed.

jpotts
World-Class Innovator
World-Class Innovator
Is there a reason you need to parse the XML in your JavaScript? If you aren't going to do anything with the XML in the controller, you'd be better off letting Freemarker handle it. Freemarker has support for XML parsing. Here's a little snippet:


<#assign xml_doc=node.xmlNodeModel>
<content>${xml_doc.@@markup}</content>
In this case I'm grabbing the XML from a node in the repo and then snagging all of the markup in that node, but you can look at a Freemarker reference for how to navigate the DOM object to extract specific elements and attributes.

Jeff

kmartino
Champ in-the-making
Champ in-the-making
Hi Jeff,

Thanks for the reply.  In my use case, I'm intending to aggregate a few XML files within Alfresco, including XSD files, into an XML document that can be used by an external Editorial UI system that will integrate with Alfresco via Webscripts.

So I need the capability to do this within JavaScript I imagine. 

Editorial UI: [external webapp that acts as proxy and editorial UI host using Alfresco ticket based authentication] <—-> Alfresco: [Alfresco Webscript aggregating XSDs, WCM Content items, additional meta data), Afresco WCM, Alfresco authentication (ticket based)] 

This resembles your docasu.sourceforge.net effort in fact!  The hope is, however, to not repeat the domain knowledge encapsulated in the XSD definitions outside of Alfresco.  They will help drive our editorial UI.

Let me know what you think,

Karl

jpotts
World-Class Innovator
World-Class Innovator
Okay, so here are a couple of things to try.

E4X doesn't like the "<?xml version="1.0" ?>" declaration, so be sure you a stripping that before you try to parse well-formed XML. In the test case in the post, the string will parse fine in E4X because it lacks the declaration. You can test this with a JavaScript controller that looks like this:
var xmlString = "<Family><Member>John</Member></Family>";
var xmlDom = new XML(xmlString);
logger.log(xmlDom.Member);
model.xml = xmlDom;

That logger statement will correctly write "John" to the log. So E4X is working fine there. But your problem is, now that you've got a DOM object, you're trying to use that from Freemarker. What you want is for the E4X DOM object to be treated like a Freemarker NodeModel, but I'm not sure that's the case.

For example, when you give Freemarker a ScriptNode that contains XML, you can easily parse it and treat it like XML like I showed in the previous post. If you look at the source code for the getXmlNodeModel method on TemplateNode that does this, you'll see that it uses Freemarker's NodeModel's parse method to parse the XML content and return it as a Freemarker NodeModel. Unless there's a utility somewhere that either does this for you for arbitrary strings, or one that converts an E4X DOM object to a Freemarker NodeModel, you may have to do it yourself. It's not a big deal to create a little class with a static method that does this and then expose that to Alfresco's JavaScript engine through Spring.

Does that help?

Jeff

kmartino
Champ in-the-making
Champ in-the-making
Hi Jeff,

It helped quite a bit.  Taking what you mentioned here into account I have a working script!  Here is an example:

Sample call:


/service/prototype/alfGetXsd?flatten=t&path=/Company%20Home/Data%20Dictionary/Web%20Forms/form1/form1.xsd

alfGetXsd.get.desc.xml:


<webscript>
  <shortname>Loads content into a freemarker model</shortname>
  <description>Loads the contents of a file into a model</description>
  <url>/prototype/alfGetXsd?nodeid={nodeid}</url>
  <url>/prototype/alfGetXsd?storeid={storeid}&amp;path={path}</url>
  <url>/prototype/alfGetXsd?flatten={flatten}&amp;path={path}</url>
  <format default="xml">argument</format>
  <transaction>required</transaction>
  <authentication>guest</authentication>
</webscript>

alfGetXsd.get.js:


// parse arguments and retrieve primary content node
if ((args.nodeid) && (args.nodeid != "")) {
   // use doc mgt nodeid
   model.node = search.findNode("workspace://SpacesStore/" + args.nodeid);
   model.emailid=model.node.properties["{http://www.alfresco.org/model/system/1.0}node-dbid"];
} else if ( (args.storeid) && (args.storeid != "") && (args.path) && (args.path != "") ) {
   // use avm storeid and path
   var store = avm.lookupStore(args.storeid);
   if (store != null) {
      var pathWithStore = args.storeid + ":" + args.path;
      model.node = avm.lookupNode(pathWithStore);
      model.emailid = "";
   }
} else {
   // use doc mgt path
   if ((args.path) && (args.path != "")) {
      model.node = roothome.childByNamePath(args.path);
      model.emailid=model.node.properties["{http://www.alfresco.org/model/system/1.0}node-dbid"];
   }
}

// make our copy
model.nodecpy = new Array();
var raw_content = new String(model.node.content);

// remove xml document declaration
index1 = raw_content.indexOf("?>");
  if (index1 > -1) {
    raw_content = raw_content.substring(index1+2);

  }

// add our adjusted copy to the model
model.nodecpy.content = new XML(new String(raw_content)).toXMLString();

// modify xml document if desired
var re = new RegExp(/<([\w]+):/);
if (model.nodecpy.content.match(re)) {
   var s = new String(model.nodecpy.content);
    if ((args.flatten) && (args.flatten == "t")) {
      s = s.replace(/<([\w]+):/g, "<$1_");
      s = s.replace(/<\/([\w]+):/g, "</$1_"); 
    }
    var x = new XML(s);
    model.nodecpy.content = x.toXMLString();
} else {
    model.noparse = "true";
}

alfGetXsd.get.xml.ftl:


${nodecpy.content}