Joining 2 Hashes/Map/Table into 1 with defined key condition in Freemarker - templates

Good Day All,
I face some situation which i have base data like this as hashes/maps/tables
And my goal is text output like this
i've tried to have code such a
<#list Detail as d>
<#list Header as h><#if H.Hno == d.DocNo>${h.Hno};${h.Htype};</#if></#list>${d.Seq};${d.Name};<#list Header as h><#if H.Hno == d.DocNo>${h.Hcode}</#if></#list>${d.Status}
</#list>
but it said somewhat Hno evaluate null or missing.
Is there any way to solve and efficient way this ?
Appreciate you guys support

Related

How do I transform this code into a list comprehension?

I have this code in Python2.7 and I wanna (if possible) transform this code into a list comprehension.
z=[]
if p==1:
z.append('a')
if m==2:
z.append('b')
print ''.join(z)
The problem is it gives me an error (syntax error) when I transformed the code like this:
z=['b' if m==2 'a' if p==1]
print ''.join(z)
Or
z=['a' if p==1 'b' if ==m]
print ''.join(z)
Please let me know if this question has a duplicate.
I would appreciate your advice.
This is a tricky one. I came up with a solution that uses enumerate and an inline if statement to tell the difference between the two if statements. Honestly, using a list comp for this will probably obfuscate the code and it'd be better to just stick with the simpler if statements you already have.
values = ['a', 'b'] # put the append arguments in here, you can also inline this but I put it apart to make the line shorter
z = [val for idx, val in enumerate(values) if (m==2 and p==1 if idx==1 else p==1)]

Stata: Efficient way to replace numerical values with string values

I have code that currently looks like this:
replace fname = "JACK" if id==103
replace lname = "MARTIN" if id==103
replace fname = "MICHAEL" if id==104
replace lname = "JOHNSON" if id==104
And it goes on for multiple pages like this, replacing an ID name with a first and last name string. I was wondering if there is a more efficient way to do this en masse, perhaps by using the recode command?
I will echo the other answers that suggest a merge is the best way to do this.
But if you absolutely must code the lines item-wise (again, messy) you can generate a long list ("pages") of replace commands by using MS Excel to "help" you write the code. Here is a picture of your Excel sheet with one example, showing the MS Excel formula:
columns:
A B C D
row: 1 last first id code
2 MARTIN JACK 103 ="replace fname=^"&B2&"^ if id=="&C2
You type that in, make sure it looks like Stata code when the formula calculates (aside from the carets), and copy the formula in column D down to the end of your list. Then copy the whole block of Stata code in column D generated by the formulas into your do-file, and do a find and replace (be careful here if you are using the caret elsewhere for mathematical uses!!) for all ^ to be replaced with ", which will end up generating proper Stata syntax.
(This is truly a brute force way of doing this, and is less dynamic in the case that there are subsequent changes to your generation list. All--apologies in advance for answering a question here advocating use of Excel :) )
You don't explain where the strings you want to add come from, but what is generally the best technique is explained at
http://www.stata.com/support/faqs/data-management/group-characteristics-for-subsets/index.html
Create an associative array of ids vs Fname,Lname
103 => JACK,MARTIN
104 => MICHAEL,JOHNSON
...
Replace
id => hash{id} ( fname & lname )
The efficiency of doing this will be taken care by the programming language used

How to use variables defined with assign in list elements in freemarker

i have a freemarker problem. I have one hash map called nodes and i iterate trough it like this:
<#list hashmap.collection as nodes>
.....some displaying
<#assign nodeName>
${nodes.name}
</#assign>
<#list hashmap2.nodeName.collection as nodes2>
.......some more displaying
And this code is not because freemarker is trying to find nodeName key inside the hashmap2...
Is there a way to do this in freemarker?
Thanks for your answers!
That should be hasmap2[nodeName].collection. What you put after . is always seen as literally the sub-variable name, while inside [] you can give an arbitrary expression as far as it evaluates to a string. Thus, you may don't need that #assign at all, and you could write hashmap2[nodes.name].collection.
Also, instead of <#assign nodeName>${nodes.name}</#assign> you should just write <#assign nodeName = nodes.name>. Again, if you need the assignment at all.
Also since nodes store a single node, your code would be more readable if you call it node.

removing BBcode from string

so it looks like this question has been asked for just about every language under the sun......except for in C++. I have an XML document that has some bbcode stored within the text node. I am looking for the best way to remove it and I thought I'd check here to see if anyone was aware of some pre-built library or some efficient method of accomplishing this myself. I was thinking of maybe deleting anything that falls between a '[' and a ']' character however, this gets insane using the XML documents that have been provided to me because many of the instances of the BB are in the form '[[blahblahblah]]' and some '[blahblahblah].'
Here is the XML document. All data between the <text> tags gets added into a string, any suggestions?
<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.7/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.7/ http://www.mediawiki.org/xml/export-0.7.xsd" version="0.7" xml:lang="en">
<page>
<title>Human Anatomy/Osteology/Axialskeleton</title>
<ns>0</ns>
<id>181313</id>
<revision>
<id>1481605</id>
<parentid>1379871</parentid>
<timestamp>2009-04-26T02:03:12Z</timestamp>
<contributor>
<username>Adrignola</username>
<id>169232</id>
</contributor>
<minor />
<comment>+Category</comment>
<sha1>hvxozde19haz4yhwj73ez82tf2bocbz</sha1>
<text xml:space="preserve"> [[Image:Axial_skeleton_diagram.svg|thumb|240px|right|Diagram of the axial skeleton]]
The Axial Skeleton is a division of the human skeleton and is named because it makes up the longitudinal ''axis'' of the body. It consists of the skull, hyoid bone, vertebral column, sternum and ribs. It is widely accepted to be made up of 80 bones, although this number varies from individual to individual.
[[Category:{{FULLBOOKNAME}}|{{FULLCHAPTERNAME}}]]</text>
</revision>
</page>
<page>
<title>Horn/General/Fingering Chart</title>
<ns>0</ns>
<id>23346</id>
<revision>
<id>1942387</id>
<parentid>1734837</parentid>
<timestamp>2010-10-02T20:21:09Z</timestamp>
<contributor>
<username>Nat682</username>
<id>144010</id>
</contributor>
<comment>added important note</comment>
<sha1>lana7m8m9r23oor0nh24ky45v71sai9</sha1>
<text xml:space="preserve">{{HornNavGeneral}}
The horn spans four plus octaves depending on the player and uses both the treble and bass clefs. In this chart it is assumed the player is using a double-horn with F and Bb sides. The number 1 indicates that the index-finger valve should be depressed, the number 2 indicates that the middle-finger valve should be depressed and the number 3 indicates that the ring-finger valve should be depressed. There are eight possible valve combinations among the first, second and third valves: 0, 1, 2, 3, 1-2, 1-3, 2-3, and 1-2-3. However, there are effectively seven combinations, because 1-2 will produce the same notes, perhaps slightly out of tune, as 3 alone. One depresses the thumb key to use the Bb side of the horn.
[[Image:Fingering chart.png]]
[[Category:Horn]]</text>
</revision>
</page>
</mediawiki>
so if you look at the bottom of each <page> tag, you will see things like [[Category:{{FULLBOOKNAME}}|{{FULLCHAPTERNAME}}]] and that's what Im looking to remove.
I'll assume the data is given to you in the form of an iterator you can read from. If you are getting it in the form of a std::string, getting an iterator you can read from is pretty easy.
In that case, what you want is a boost filter_iterator: http://www.boost.org/doc/libs/1_39_0/libs/iterator/doc/filter_iterator.html
The filter function you want is pretty easy. You keep track of how many [ you have seen and subtract how many ] you have seen (stopping at 0). While your count is positive, you filter out the character.
If you cannot use boost, but you are getting it from a std::string, well, that is a bit trickier. But only a bit. std::copy_if works.
If you are using C++11, a lambda makes this really easy. If not, you'll have to write your own functor that counts [s.
As a concrete example of a simple case: you are being fed a std::string and want to produce a std::string without any [] delimited contents.
struct SquareBracketStripper
{
enum { open_bracket = '[', close_bracket = ']' };
size_t count;
SquareBracketStripper():count(0) {}
bool operator()(char c)
{
bool skip = (count > 0) || c == open_bracket;
if (c == open_bracket) {
++count;
} else if (c== close_bracket && count > 0) {
--count;
}
return skip;
}
};
std::string FilterBBCode( std::string input ) {
input.erase(input.end(), std::remove_if( input.begin(), input.end(), SquareBracketStripper() ) );
return input;
}
which handles arbitrary depths of nested []s.
The filter_iterator helps in that you never have to have the entire string loaded into memory, which is useful if you don't know how malformed your input will be. Loading a few terrabytes of data from disk into memory just to filter out [] is not needed, when you could stream the stuff and do the filtering on the fly. But your use case may not really care.

Regular expression to get HTML table contents

I've stumbled on a bit of challenge here: how to get the contents of a table in HTML with the help of a regular expression. Let's say this is our table:
<table someprop=2 id="the_table" otherprop="val">
<tr>
<td>First row, first cell</td>
<td>Second cell</td>
</tr>
<tr>
<td>Second row</td>
<td>...</td>
</tr>
<tr>
<td>Another row, first cell</td>
<td>Last cell</td>
</tr>
</table>
I already found a method that works, but involves multiple regular expression to be executed in steps:
Get the right table and put it's rows in back-reference 1 (there may be more than one in the document):
<table[^>]*?id="the_table"[^>]*?>(.*?)</table>
Get the rows of the table and put the cells in back-reference 1:
<tr.*?>(.*?)</tr>
And lastly fetch the cell contents in back-reference 1:
<td.*?>(.*?)</td>
Now this is all good, but it would be infinitely more awesome to do this all using one fancy regular expression... Does someone know if this is possible?
There really isn’t a possible regex solution that works for an arbitrary number of table data and puts each cell into a separate back reference. That’s because with backreferences, you need to have a distinct open paren for each backref you want to create, and you don’t know how many cells you have.
There’s nothing wrong with using looping of one or another sort to pull out the data. For example, on the last one, in Perl it would be this, given that $tr already contains the row you need:
#td = ( $tr =~ m{<td.*?>(.*?)</td>}sg );
Now $td[0] will contain the first <td>, $td[1] will contain the second one, etc. If you wanted a two-dimensional array, you might wrap that in a loop like this to populate a new #cells variable:
our $table; # assume has full table in it
my #cells;
while(my($tr) =~ $table = m{<tr.*?>(.*?)</tr>}sg) {
push #cells, [ $tr =~ m{<td.*?>(.*?)</td>}sg ];
}
Now you can do two-dimensional addressing, allowing for $cells[0][0], etc. The outer explicit loop processes the table a row at a time, and the inner implicit loop pulls out all the cells.
That will work on the canned sample data you showed. If that’s good enough for you, then great. Use it and move on.
What Could Ever Be Wrong With That?
However, there are actually quite a few assumptions in your patterns about the contents of your data, ones I don’t know that you’re aware of. For one thing, notice how I’ve used /s so that it doesn’t get stuck on newlines.
But the main problem is that minimal matches aren’t always quite what you want here. At least, not in the general case. Sometimes they aren’t as minimal as you think, matching more than you want, and sometimes they just don’t match enough.
For example, a pattern like <i>(.*?)</i> will get more than you want if the string is:
<i>foo<i>bar</i>ness</i>
Because you will end up matching the string <i>foo<i>bar</i>.
The other common problem (and not counting the uncommon ones) is that a pattern like <tag.*?> may match too little, such as with
<img alt=">more" src="somewhere">
Now if you use a simplistic <img.*?> on that, you would only capture <img alt=">, which is of course wrong.
I think the last major remaining problem is that you have to altogether ignore certain things in parsing. The simplest demo of this embedded comments (also <script>, <style>, andCDATA`), since you could have something like
<i> some <!-- secret</i> --> stuff </i>
which will throw off something like <i>(.*?)</i>.
There are ways around all these, of course. Once you’ve done so, and it is really quite a bit of effort, you’ll find that you have built yourself a real parser, completely with a lot of auxiliary logic, not just one pattern.
Even then you are only processing well-formed input strings. Error recovery and failing softly is an entirely different art.
This answer was added before it was known the the OP needed a solution for c++...
Since using regex to parse html is technically wrong, I'll offer a better solution. You could use js to get the data and put it into a two dimensional array. I use jQuery in the example.
var data = [];
$('table tr').each(function(i, n){
var $tr = $(n);
data[i] = [];
$tr.find('td').text(function(j, text){
data[i].push(text);
});
});
jsfiddle of the example: http://jsfiddle.net/gislikonrad/twzM7/
EDIT
If you want a plain javascript way of doing this (not using jQuery), then this might be more for you:
var data = [];
var rows = document.getElementById('the_table').getElementsByTagName('tr');
for(var i = 0; i < rows.length; i++){
var d = rows[i].getElementsByTagName('td');
data[i] = [];
for(var j = 0; j < d.length; j++){
data[i].push(d[j].innerText);
}
}
Both these functions return the data the same way.