I am new to StringTemplate template engine and want to use it for generating an html document with a table. I want to alter the style of the table rows depending on whether it is odd or even. I found a discussion on the stringtemplate-interest mailing list that describes the general approach ([stringtemplate-interest] Odd even row formatting).
But I have an additional requirement which breaks this general approach (I think). I want to render rows depending on the existence of a value. So I am working with a conditional expression $if(expr)$. My template looks like this.
delimiters „$“,“$“
htmlTable(valueA, valueB, valueC, valueD) ::= <<
<table>
<tr styleClass='odd'><td>$valueA$</td></tr>
$if(valueB)$
<tr><td>$valueB$</td></tr>
$endif$
<tr styleClass='odd'><td>$valueC$</td></tr>
<tr><td>$valueD$</td></tr>
</table>
>>
In the given template I can not use the hard coded styleClass attribute, because it would render the table wrong if the valueB parameter does not exist.
Is my requirement realizable with a template engine like StringTemplate, which focus on separation of model and view? Or is there too much model in the requirement as to implement it in the view? I know how to do it in other template engines (i. e. FreeMarker or Apache Velocity) or I might use some fancy CSS or javascript stuff but I would rather keep the model-view separation and use StringTemplates internal instruments.
Related
I have a MediaWiki site hosted on ShoutWiki. I want to create a template that will return a table, with rows filtered by the template's single argument. The table could be stored in whatever format works. It will have three columns, and I want to display rows only if the template's argument is a substring of the text in the first cell in the row. The search needs to be case sensitive.
There are JavaScript solutions for this, but I'd like to do it on the server if possible.
If you don't have a special extension handling that (e.g. Scribunto adding Lua support and therefore a real programming language to MediaWiki), you need to encapsulate each row into an own template call.
Example:
Template:FilteredRow
{{#ifeq:{{{1|}}}|{{{2|}}}|<tr><td>{{{2|empty row}}}</tr></td> }}
Template:A_Table
<table>
{{FilteredRow|1={{{filter|}}}|2=some content here}}
{{FilteredRow|1={{{filter|}}}|2=some content here in row 2}}
{{FilteredRow|1={{{filter|}}}|2=some content here in row 3}}
{{FilteredRow|1={{{filter|}}}|2=baz}}
</table>
Using:
{{A_Table|filter=baz}}
Result:
<table>
<tr><td>baz</td></tr>
</table>
With Scribunto, you could simply save your table as HTML table, or JSON, or whatever parser you find. Note that JSON support (recognition, formatting, validation) in MediaWiki and user namespace is being worked on.
I have a table that stores html templates in a mysql database. Now I have to perform some text replacement on them. However my target text is also present in some of the anchor tags and I don't want that to be replaced.
EX :
<body> ... (has huge html crap)... .........(Some more html crap) ... (a bit more of html crap) ... </body>
Task is to replace the occurrences of the "KEYWORD" with "NEW KEYWORD" in the body but not the urls.
It would also be helpful if I can first find such cases where the KEYWORD is a part of a link in a given template.
MySQL is not capable of such advanced string manipulation.
However, if you were to have a one-time-use PHP script do the editing (ie. select from the table, for each row process and update), you can do this:
// foreach row as $row
$newtext = preg_replace("(<a\b.*?>(*SKIP)(*FAIL)|KEYWORD)","NEW KEYWORD",$row['data']);
What this does is look for links (very approximate Regex but should suffice in almost all cases here), then skip over them. Then, it looks for KEYWORD and replaces it with NEW KEYWORD.
You can use this to quickly and easily handle the replacement.
If that "almost all cases" thing above turns out to not be enough, you can use DOMDocument to load the HTML into a parser and process text nodes only from there.
Maybe you could find the cases where the KEYWORD is a part of a link with something like this:
SELECT * FROM tbl WHERE html REGEXP '<a[^>]*KEYWORD';
I am looking to avoid using xpaths that are 'xpath position'. Reason being, the xpath can change and fail an automation test if a new object is on the page and shifts the expected xpath position.
But on some web pages, this is the only xpath I can find. For example, I am looking to click a tab called 'FooBar'.
If I use the Selenium IDE FireFox plugin, I get:
//td[12]/a/font
If I use the FirePath Firefox plugin, I get:
html/body/form/table[2]/tbody/tr/td[12]/font
If a new tab called "Hello, World" is added to the web page (before FooBar tab) then FooBar tab will change and have an xpath position of
//td[13]/a/font
What would you suggest to do?
TY!
Instead of using absolute xpath you could use relateive xpath which is short and more reliable.
Say
<td id="FooBar" name="FooBar">FooBar</td>
By.id("FooBar");
By.name("FooBar");
By.xpath("//td[text()='FooBar']") //exact match
By.xpath("//td[#id='FooBar']") //with any attribute value
By.xpath("//td[contains(text(),'oBar')]") //partial match with contains function
By.xpath("//td[starts-with(text(),'FooB')]") //partial match with startswith function
This blog post may be useful for you.
Relative xpath is good idea. relative css is even better(faster)
If possible suggest/request id for element.
Check also chrome -> check element -> copy css/xpath
Using //td is not a good idea because it will return all your td nodes. Any predicate such as //td[25] will be a very fragile selection because any td added to any previous table will change its result. Using plugins to generate XPath is great to find quickly what you want, but its always best to use it just as a starting point, and then analyze the structure of the file to write a locator that will be harder to break when changes occur.
The best locators are anchored to invariant values or attributes. Plugins usually won't suggest id or attribute anchors. They usually use absolute positional expressions. If can rewrite your locator path in terms of invariant structures in the file, you can then select the elements or text that you want relative to it.
For example, suppose you have
<body> ...
... lots of code....
<h1>header that has a special word</h1>
... other tags and text but not `h1` ...
<table id="some-id">
...
<td>some-invariant-text</td>
<td>other text</td>
<td>the field that you want</td>
...
The table has an ID. That's the best anchor. Now you can select the table as
//table[#id='some-id']
But many times you don't have the id, or even some other invariant attribute. You can still try to discover a pattern. For example: suppose that the last <h1> before the table you want contains a word you can match, you could still find the table using:
//table[preceding::h1[1][contains(.,'word')]]
Once you have the table, you can use relative axes to find the other nodes. Let's assume you want an td but there are no attributes on any tbody, tr, etc. You can still look for some invariant text. Tables usually have headers, or some fixed text which you can match. In the example above, if you find a td that is 2 fields before the one that you want, you could use:
//table[preceding::h1[1][contains(.,'word')]]/td[preceding-sibling::td[2][.='some-invariant-text']]
This is a simple example. If you apply some of these suggestions to the file you are working on, you can improve your XPath expression and make your selection code more robust.
I've searched but cannot find an answer.
How do I print an HTML Table with page breaks based on the value of a particular cell.
Basically I want to print a list of addresses and have a new page when the road name changes.
You can’t do this in HTML or in CSS. You need to mark the page breaks when generating the table or with client-side JavaScript. In either case, you just need to store the road name (which you need to get from somewhere according to the structure of the date). When processing a new row, you then just check the road name in its data against the stored value, and if they differ, emit
<tr style="page-break-before: always">
instead of a simple <tr> or, when doing this client-side, modify the style property of the tr element node accordingly.
The variable strCSSClass often has a value but sometimes is empty.
I do not want to include an empty class="" in this input element's HTML, which means if strCSSClass is empty, I don't want the class= attribute at all.
The following is one way to do a conditional HTML attribute:
<input type="text" id="#strElementID" #(CSSClass.IsEmpty() ? "" : "class=" + strCSSClass) />
Is there a more elegant way of doing this? Specifically one where I could follow the same syntax as is used in the other parts of the element: class="#strCSSClass" ?
You didn't hear it from me, the PM for Razor, but in Razor 2 (Web Pages 2 and MVC 4) we'll have conditional attributes built into Razor (as of MVC 4 RC tested successfully), so you can write things like this:
<input type="text" id="#strElementID" class="#strCSSClass" />
If strCSSClass is null then the class attribute won't render at all.
Further Reading
Jon Galloway - ASP.NET MVC 4 Beta Released!
Conditional Attributes in Razor View Engine and ASP.NET MVC 4
Note you can do something like this(at least in MVC3):
<td align="left" #(isOddRow ? "class=TopBorder" : "style=border:0px") >
What I believed was razor adding quotes was actually the browser. As Rism pointed out when testing with MVC 4(I haven't tested with MVC 3 but I assume behavior hasn't changed), this actually produces class=TopBorder but browsers are able to parse this fine. The HTML parsers are somewhat forgiving on missing attribute quotes, but this can break if you have spaces or certain characters.
<td align="left" class="TopBorder" >
OR
<td align="left" style="border:0px" >
What goes wrong with providing your own quotes
If you try to use some of the usual C# conventions for nested quotes, you'll end up with more quotes than you bargained for because Razor is trying to safely escape them. For example:
<button type="button" #(true ? "style=\"border:0px\"" : string.Empty)>
This should evaluate to <button type="button" style="border:0px"> but Razor escapes all output from C# and thus produces:
style="border:0px"
You will only see this if you view the response over the network. If you use an HTML inspector, often you are actually seeing the DOM, not the raw HTML. Browsers parse HTML into the DOM, and the after-parsing DOM representation already has some niceties applied. In this case the Browser sees there aren't quotes around the attribute value, adds them:
style=""border:0px""
But in the DOM inspector HTML character codes display properly so you actually see:
style=""border:0px""
In Chrome, if you right-click and select Edit HTML, it switch back so you can see those nasty HTML character codes, making it clear you have real outer quotes, and HTML encoded inner quotes.
So the problem with trying to do the quoting yourself is Razor escapes these.
If you want complete control of quotes
Use Html.Raw to prevent quote escaping:
<td #Html.Raw( someBoolean ? "rel='tooltip' data-container='.drillDown a'" : "" )>
Renders as:
<td rel='tooltip' title='Drilldown' data-container='.drillDown a'>
The above is perfectly safe because I'm not outputting any HTML from a variable. The only variable involved is the ternary condition. However, beware that this last technique might expose you to certain security problems if building strings from user supplied data. E.g. if you built an attribute from data fields that originated from user supplied data, use of Html.Raw means that string could contain a premature ending of the attribute and tag, then begin a script tag that does something on behalf of the currently logged in user(possibly different than the logged in user). Maybe you have a page with a list of all users pictures and you are setting a tooltip to be the username of each person, and one users named himself '/><script>$.post('changepassword.php?password=123')</script> and now any other user who views this page has their password instantly changed to a password that the malicious user knows.
I guess a little more convenient and structured way is to use Html helper. In your view it can be look like:
#{
var htmlAttr = new Dictionary<string, object>();
htmlAttr.Add("id", strElementId);
if (!CSSClass.IsEmpty())
{
htmlAttr.Add("class", strCSSClass);
}
}
#* ... *#
#Html.TextBox("somename", "", htmlAttr)
If this way will be useful for you i recommend to define dictionary htmlAttr in your model so your view doesn't need any #{ } logic blocks (be more clear).