Need to create a .doc file with list of items using Aspose - aspose

I have been working on legacy application where i am using Aspose.Words.jdk15.jar to print the .doc file. I have a requirement where i am getting list of value then we have to loop & print it in the doc file.
And that value we are replacing in doc using range.replace() method . This doc already exists in my workspace where we have mapped the value like this
Component Name:$COMPONENT_NAME
Billing Effective Date:$EFFECTIVE_DATE
Billing End Date:$END_DATE
and the code which i have written to replace the value of doc. So, my requirement is I need this value multiple times in my doc as per size of list.
for(int i=0;i<details.size();i++)
{
doc.getRange().replace("$COMPONENT_NAME" , checkNull(details.get(i).getComponentName()) + “,”, false, false);
doc.getRange().replace("$EFFECTIVE_DATE" , checkNull(details.get(i).getBillEffectiveDate()) + “,”, false, false);
doc.getRange().replace("$END_DATE" , checkNull(details.get(i).getBillEndDate()) + “,”, false, false);
}

The best way to achieve what you need is using mail Merge feature.
https://docs.aspose.com/words/java/about-mail-merge/
But in this case you need to replace your placeholders with mergefields in your template.
If you cannot change the template, you can clone the the document for each item in your list, replace values in the cloned document and them merge documents together to get the final result. Code will look like the following:
// Open template
Document doc = new Document("C:\\Temp\\in.doc");
// Create document where result will be stored to.
// Simply clone the original template without children,
// In this case styles of the original document will be kept.
Document result = (Document)doc.deepClone(false);
for(int i=0; i<details.length; i++)
{
Document component = doc.deepClone();
component.getRange().replace("$COMPONENT_NAME", details[i].getComponentName());
component.getRange().replace("$EFFECTIVE_DATE", details[i].getBillEffectiveDate().toString());
component.getRange().replace("$END_DATE", details[i].getBillEndDate().toString());
// Append the result to the final document.
result.appendDocument(component, ImportFormatMode.USE_DESTINATION_STYLES);
}
result.save("C:\\Temp\\out.doc");
But I would preferer Mail Merge approach.

Related

Get filename in Dynamics Ax

I need to extract a file name from complete path and I see it strange that I when I split the path, I need to iterate through the list to get the file name. Why can't I just get the value simply by calling myList(3) as in DotNet, instead of having to instantiate an iterator, then loop through the records.
Here is my code;
List strlist=new List(Types::String);
strlist = strSplit(CompletePath, #"\");
After doing this I should have a list of all the different parts.
Is there any simple form to read the list, like FileName = strlist[2]; instead of having to do the below;
iterator = new ListIterator(strlist);
while(iterator.more())
{
FileName = iterator.value();
if (_Value == "myFile")
{
_NotFound=boolean::false;
}
Here again, if at that very moment, I don't know the file name, how do I check?
Global::fileNameSplit(fileName)
returns a container [path, file name, extension]
Should be used over the .NET methods recommended by Matej.
Use System.IO.Path::GetFileName(CompletePath) or System.IO.Path::GetFileNameWithoutExtension.

How to read word each page?

I know doc.Save() function save all page in one HTML file.
doc.RenderToScale() function save each page to the independent image file.
but i want read or save each page in independent HTML file,I had not idea,can you help me?
You can use the following code sample to convert each page to HTML or any other format supported by Aspose.Words.
String srcDoc = Common.DATA_DIR + "src.docx";
String dstDoc = Common.DATA_DIR + "dst {PAGE_NO}.html";
Document doc = new Document(srcDoc);
LayoutCollector layoutCollector = new LayoutCollector(doc);
// This will build layout model and collect necessary information.
doc.updatePageLayout();
// Split nodes in the document into separate pages.
DocumentPageSplitter splitter = new DocumentPageSplitter(layoutCollector);
// Save each page to disk as separate documents.
for (int page = 1; page <= doc.getPageCount(); page++)
{
Document pageDoc = splitter.getDocumentOfPage(page);
pageDoc.save(dstDoc.replace("{PAGE_NO}", page+""));
}
It depends on 3 other classes, which you can find in this zip file.
I work with Aspose as Developer Evangelist.

Sitecore Multisite Manager and 'source' field in template builder

Is there any way to parametise the Datasource for the 'source' field in the Template Builder?
We have a multisite setup. As part of this it would save a lot of time and irritation if we could point our Droptrees and Treelists point at the appropriate locations rather than common parents.
For instance:
Content
--Site1
--Data
--Site2
--Data
Instead of having to point our site at the root Content folder I want to point it at the individual data folders, so I want to do something like:
DataSource=/sitecore/content/$sitename/Data
I can't find any articles on this. Is it something that's possible?
Not by default, but you can use this technique to code your datasources:
http://newguid.net/sitecore/2013/coded-field-datasources-in-sitecore/
You could possibly use relative paths if it fits with the rest of your site structure. It could be as simple as:
./Data
But if the fields are on random items all over the tree, that might not be helpul.
Otherwise try looking at:
How to use sitecore query in datasource location? (dynamic datasouce)
You might want to look at using a Querable Datasource Location and plugging into the getRenderingDatasource pipeline.
It's really going to depend on your use cases. The thing I like about this solution is there is no need to create a whole bunch of controls which effectively do he same thing as the default Sitecore ones, and you don't have to individually code up each datasource you require - just set the query you need to get the data. You can also just set the datasource query in the __standard values for the templates.
This is very similar to Holger's suggestion, I just think this code is neater :)
Since Sitecore 7 requires VS 2012 and our company isn't going to upgrade any time soon I was forced to find a Sitecore 6 solution to this.
Drawing on this article and this one I came up with this solution.
public class SCWTreeList : TreeList
{
protected override void OnLoad(EventArgs e)
{
if (!String.IsNullOrEmpty(Source))
this.Source = SourceQuery.Resolve(SContext.ContentDatabase.Items[ItemID], Source);
base.OnLoad(e);
}
}
This creates a custom TreeList control and passes it's Source field through to a class to handle it. All that class needs to do is resolve anything you have in the Source field into a sitecore query path which can then be reassigned to the source field. This will then go on to be handled by Sitecore's own query engine.
So for our multi-site solution it enabled paths such as this:
{A588F1CE-3BB7-46FA-AFF1-3918E8925E09}/$sitename
To resolve to paths such as this:
/sitecore/medialibrary/Product Images/Site2
Our controls will then only show items for the correct site.
This is the method that handles resolving the GUIDs and tokens:
public static string Resolve(Item item, string query)
{
// Resolve tokens
if (query.Contains("$"))
{
MatchCollection matches = Regex.Matches(query, "\\$[a-z]+");
foreach (Match match in matches)
query = query.Replace(match.Value, ResolveToken(item, match.Value));
}
// Resolve GUIDs.
MatchCollection guidMatches = Regex.Matches(query, "^{[a-zA-Z0-9-]+}");
foreach (Match match in guidMatches)
{
Guid guid = Guid.Parse(match.Value);
Item queryItem = SContext.ContentDatabase.GetItem(new ID(guid));
if (item != null)
query = query.Replace(match.Value, queryItem.Paths.FullPath);
}
return query;
}
Token handling below, as you can see it requires that any item using the $siteref token is inside an Site Folder item that we created. That allows us to use a field which contains the name that all of our multi-site content folders must follow - Site Reference. As long at that naming convention is obeyed it allows us to reference folders within the media library or any other shared content within Sitecore.
static string ResolveToken(Item root, string token)
{
switch (token)
{
case "$siteref":
string sRef = string.Empty;
Item siteFolder = root.Axes.GetAncestors().First(x => x.TemplateID.Guid == TemplateKeys.CMS.SiteFolder);
if (siteFolder != null)
sRef = siteFolder.Fields["Site Reference"].Value;
return sRef;
}
throw new Exception("Token '" + token + "' is not recognised. Please disable wishful thinking and try again.");
}
So far this works for TreeLists, DropTrees and DropLists. It would be nice to get it working with DropLinks but this method does not seem to work.
This feels like scratching the surface, I'm sure there's a lot more you could do with this approach.

Search Informatica for text in SQL override

Is there a way to search all the mappings, sessions, etc. in Informatica for a text string contained within a SQL override?
For example, suppose I know a certain stored procedure (SP_FOO) is being called somewhere in an INFA process, but I don't know where exactly. Somewhere I think there is a Post SQL on a source or target calling it. Could I search all the sessions for Post SQL containing SP_FOO ? (Similar to what I could do with grep with source code.)
You can use Repository queries for querying REPO tables(if you have enough access) to get data related with all the mappings,transformations,sessions etc.
Please use the below link to get almost all kind of repo queries.Ur answers can be find in the below link.
https://uisapp2.iu.edu/confluence-prd/display/EDW/Querying+PowerCenter+data
select *--distinct sbj.SUBJECT_AREA,m.PARENT_MAPPING_NAME
from REP_SUBJECT sbj,REP_ALL_MAPPINGS m,REP_WIDGET_INST w,REP_WIDGET_ATTR wa
where sbj.SUBJECT_ID = m.SUBJECT_ID AND
m.MAPPING_ID = w.MAPPING_ID AND
w.WIDGET_ID = wa.WIDGET_ID
and sbj.SUBJECT_AREA in ('TLR','PPM_PNLST_WEB','PPM_CURRENCY','OLA','ODS','MMS','IT_METRIC','E_CONSENT','EDW','EDD','EDC','ABS')
and (UPPER(ATTR_VALUE) like '%PSA_CONTACT_EVENT%'
-- or UPPER(ATTR_VALUE) like '%PSA_MEMBER_CHARACTERISTIC%'
-- or UPPER(ATTR_VALUE) like '%PSA_REPORTING_HH_CHRSTC%'
-- or UPPER(ATTR_VALUE) like '%PSA_REPORTING_MEMBER_CHRSTC%'
)
--and m.PARENT_MAPPING_NAME like '%ARM%'
order by 1
Please let me know if you have any issues.
Another less scientific way to do this is to export the workflow(s) as XML and use a text editor to search through them for the stored procedure name.
If you have read access to the schema where the informatica repository resides, try this.
SELECT DISTINCT f.subj_name folder, e.mapping_name, object_type_name,
b.instance_name, a.attr_value
FROM opb_widget_attr a,
opb_widget_inst b,
opb_object_type c,
opb_attr d,
opb_mapping e,
opb_subject f
WHERE a.widget_id = b.widget_id
AND b.widget_type = c.object_type_id
AND ( object_type_name = 'Source Qualifier'
OR object_type_name LIKE '%Lookup%'
)
AND a.widget_id = b.widget_id
AND a.attr_id = d.attr_id
AND c.object_type_id = d.object_type_id
AND attr_name IN ('Sql Query')--, 'Lookup Sql Override')
AND b.mapping_id = e.mapping_id
AND e.subject_id = f.subj_id
AND a.attr_value is not null
--AND UPPER (a.attr_value) LIKE UPPER ('%currency%')
Yes. There is a small java based tool called Informatica Meta Query.
Using that tool, you can search for any information that is present in the Informatica meta data tables.
If you cannot find that tool, you can write queries directly in the Informatica Meta data tables to get the required information.
Adding few more lines to solution provided by Data Origin and Sandeep.
It is highly advised not to query repository tables directly. Rather, you can create synonyms or views and then query those objects to avoid any damage to rep tables.
In our dev/ prod environment application programmers are not granted any direct access to repo. tables.
As querying the Informatica database isn't the best idea, I would suggest you to export all the workflows in your folder into xml using Repository Manager. From Rep Mgr you can select all of them once and export them at once. Then write a java program to search the pattern from the xml's you have.
I have written a sample prog here, please modify it as per your requirement:
make a spec file with workflow names(specFileName).
main()
{
try {
File inFile = new File(specFileName);
BufferedReader reader = new BufferedReader(newFileReader(infile));
String tectToSearch = '<YourString>';
String currentLine;
while((currentLine = reader.readLine()) != null)
{
//trim newline when comparing with String
String trimmedLine = currentLine.trim();
if(currentline has the string pattern)
{
SOP(specFileName); //specfile name
}
}
reader.close();
}
catch(IOException ex)
{
System.out.println("Error reading to file '" + specFileName +"'");
}
}

Data loop using nodejs mailer template

I'm using node.js mailer module to send email template. I manage to send the template with the correct json replacements to the designated email address.
However, I am wondering if there's a shortcut to set the values of the replacement when there's too many similar replacements.
For example, i have an object "userNameList". It contains a list of usernames. I want to send the list of usernames using an email template. Instead of...
data: {
"username1":userNameList[1],
"username2":userNameList[2],
"username3":userNameList[3],
"username4":userNameList[4],
"username5":userNameList[5],
"username6":userNameList[6],
...
"username100":userNameList[100]
}
Is there a way to reduce the number of lines and for the code to work more effectively?
thanks.
You can use the following:
data = {};
for(var i=0; i<userNameList.length; i++) {
data["username" + (i+1)] = userNameList[i]; // Array indexes start at 0
}