Hello all you smart people of StackOverflow.
I was given a task yesterday to convert this scanned image to PDF document.
As I don't have time to learn all tips and tricks of iText, I decided to use xmlWorker and create an HTML template of the document itself.
I was quite successful, the ending result is this:
HOWEVER!
Not everything went smoothly. If you take a closer look at the scanned document, you may notice that in the middle of the document there is a table with dashed border. And this is where my headache starts.
I've been googling for the past 15 hrs trying to find a solution for this, but was not successful. I've tried all kinds of CSS border definitions like:
border-left-style: dashed;
border-style: dashed;
border: dashed;
It seems that these CSS definitions are simply ignored.
So my question is this, is there a proper way to define an HTML table with dashed border so it can be properly converted to PDF document?
I am using latest iTextSharp from Nuget (v. 5.5.12).
Thank you in advance.
Edit:
Ok, so 24 hrs later I think I have an answer.
It is a combination of these two examples:
http://codejaxy.com/q/395523/c-23-html-asp-net-itextsharp-xmlworker-using-itextsharp-xmlworker-to-convert-html-to-pdf-and-write-text-vertically
One cell with different border types
Basically I implemented IPdfPCellEvent interface so I could use a CellEvent on a PdfCell:
public class DottedCell : IPdfPCellEvent
{
private readonly int _border = 0;
public DottedCell(int border)
{
_border = border;
}
public void CellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases)
{
var canvas = canvases[PdfPTable.LINECANVAS];
canvas.SaveState();
canvas.SetLineDash(0, 2, 2);
cell.Border = Rectangle.NO_BORDER;
if ((_border & Rectangle.TOP_BORDER) == Rectangle.TOP_BORDER)
{
canvas.MoveTo(position.GetRight(1), position.GetTop(1));
canvas.LineTo(position.GetLeft(1), position.GetTop(1));
}
if ((_border & Rectangle.BOTTOM_BORDER) == Rectangle.BOTTOM_BORDER)
{
canvas.MoveTo(position.GetRight(1), position.GetBottom(1));
canvas.LineTo(position.GetLeft(1), position.GetBottom(1));
}
if ((_border & Rectangle.RIGHT_BORDER) == Rectangle.RIGHT_BORDER)
{
canvas.MoveTo(position.GetRight(1), position.GetTop(1));
canvas.LineTo(position.GetRight(1), position.GetBottom(1));
}
if ((_border & Rectangle.LEFT_BORDER) == Rectangle.LEFT_BORDER)
{
canvas.MoveTo(position.GetLeft(1), position.GetTop(1));
canvas.LineTo(position.GetLeft(1), position.GetBottom(1));
}
canvas.Stroke();
canvas.RestoreState();
}
}
After that I overrode a iTextSharp.tool.xml.html.table.TableData class:
public class TableDataProcessor : TableData
{
bool HasBorderStyle(IDictionary<string, string> attributeMap, string borderPosition, string borderStyle)
{
var hasStyle = attributeMap.ContainsKey("style");
if (!hasStyle)
{
return false;
}
var borderLeft = attributeMap["style"]
.Split(';')
.FirstOrDefault(o => o.Trim().StartsWith("border-style-" + borderPosition + ":"));
if (borderLeft != null)
{
return borderLeft.Split(':').Any(o => o.Trim().ToLower() == borderStyle);
}
return false;
}
public override IList<IElement> End(IWorkerContext ctx, Tag tag, IList<IElement> currentContent)
{
var cells = base.End(ctx, tag, currentContent);
var attributeMap = tag.Attributes;
if (HasBorderStyle(attributeMap, "left", "dotted"))
{
var pdfPCell = (PdfPCell) cells[0];
pdfPCell.CellEvent = null;
pdfPCell.CellEvent = new DottedCell(Rectangle.LEFT_BORDER);
}
return cells;
}
}
The last step was to add that class to tag processor for a TD element:
var tagProcessorFactory = Tags.GetHtmlTagProcessorFactory();
tagProcessorFactory.AddProcessor(
new TableDataProcessor(),
new[] {HTML.Tag.TD}
);
htmlContext.SetTagFactory(tagProcessorFactory);
And it works:
HTML markup:
<table class="content-wrapper">
<tbody>
<tr>
<td class="pcnt_60 content-left top" valign="top">
<table>
<tr>
<td style='border-left: 0.5px; border-style-left: dotted;'>content goes here</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
Related
I would like to change the color in the (td) field [change color - change / transfer to a different css class?]
Condition:
The condition comes from the "if" query. if (sb == true) then nothing changes, if (sb == false) "[else]"
then the css class in (td class="InputsForUserColor1") may change to class="InputsForUserColor1Change".
Notes
(td class="InputsForUserColor2") is unchanged
My html code (razor/C#):
the variable "sb" is outside "if", assumes a different value
#for (int sth = 0; sth< ViewBag.sth; sth++)
{
if (sb == true)
{
varSth = "00:00";
}
else
{
varSth = "20:00";
}
#for (int sthElse = 0; sthElse< ViewBag.sthElse; sthElse++)
{
if (nr_columns == 2)
{
<td id="td01" class="InputsForUserColor1"></td>
}
if (nr_columns == 3)
{
<td id="td01" class="InputsForUserColor2"></td>
}
}
}
My CSS code:
.InputsForUserColor1, area {
background-color: papayawhip;
border: hidden;
align-content: center;
align-items: center;
vertical-align: central;
}
.InputsForUserColor1Change, area {
background-color: white;
border: hidden;
align-content: center;
align-items: center;
vertical-align: central;
}
personally I didn't write it because I don't know how to approach it
If the color should only be set once, while the page is rendered on the server:
set the target class in a variable of the CSHMTL page (Razor C# code block with #{}).
use the value of this variable (Razor #variableName Syntax).
#* assume that 'sb' does not change its value inside the for loop *#
#{ var userColor1 = sb == true ? "InputsForUserColor1" : "InputsForUserColor1Change"; }
#for (int sth = 0; sth< ViewBag.sth; sth++) {
#for (int sthElse = 0; sthElse< ViewBag.sthElse; sthElse++) {
if (nr_columns == 2) {
<td id="td01" class="#userColor1"></td>
}
else if (nr_columns == 3) {
<td id="td01" class="InputsForUserColor2"></td>
}
}
}
This will render the HTML with the correct class set when the page is delivered to the client browser.
This will not work if the color needs to change due to user interactions on the client (browser) side. In this case, you have to use a client script (JavaScript) to change the color dynamically. To do this, see jQuery addClass.
Pardon me if my question title is not expressive ,but what I want to say is I have a simple tool that should search in a website and get the result which is 3 kinds of data (name,phone,address) I had written some codes for opening the website inside web browser tool and applied a loop statement to search for 30 numbers and it really works but the problem is it works for only one time and the second problem is in retrieving data from the other page which opens when the search button is clicked ,so suppose that I will start my sequential based number in search as 737000000 it should search for this number and opens the other page which contains the data and put these data in 3 text boxes finally back to previous page and search for 737000001 (adding 1 each time)
My codes are
private void searchBtn_Click(object sender, EventArgs e)
{
for (int i = 0; i < 30; i++)
{
string temp = string.Format("{0:D6}", i);
string formula = textBox1.Text + temp;
// Get all input elements
HtmlElementCollection inputs = webBrowser1.Document.GetElementsByTagName("input");
// Select "txtSearch" input
HtmlElement input = inputs["q"];
if (input != null)
{
string value = input.GetAttribute("VALUE");
if (!string.IsNullOrEmpty(value))
{
// Already searched but no results
}
else
{
// Input search text
string searchText = formula;
input.SetAttribute("VALUE", searchText);
var elements = webBrowser1.Document.GetElementsByTagName("button");
foreach (HtmlElement element in elements)
{
element.InvokeMember("click");
}
}
}
}
the data in the other page when I view the page source appears like
<table class="table table-responsive table-striped">
<thead>
<tr>
<th>name</th>
<th>number</th>
<th>address</th>
</tr>
</thead>
<tbody>
<tr>
<td>Mat Adam</td>
<td><b class="text-success">737000000</b></td>
<td>New York</td>
</tr> </tbody>
</table>
Hello i trying to make click on element 'a' with WatiN(dll) and i can't get to this element to make click.Privous clicks works fine, but this one is not working
here my code
var browser = new IE("https://www.tesst.com");
browser2.TableRow(Find.ById("kyos_filaCuenta_00")).FireEvent("onmouseover");
browser2.Link(Find.ById("kyos_enlaceIrAMovsCuenta_EUR0")).Click();
/*i tried this one too
TableCell tb = browser2.TableCell(Find.ByClass("kyos_positionFirstElementTd ancho200 columna0"));
Link link = tb.Link(lnk => lnk.GetAttributeValue("onclick").ToLower().Contains(".close(true)"));
link.Click();
*/
Here Html page
<tbody>
<tr id="kyos_filaCuenta_00" class="cuentaNoFavorita">
<td class="ancho20 kyos_anchoCheckTd">
<td class="kyos_positionFirstElementTd ancho200 columna0">
<a id="kyos_enlaceIrAMovsCuenta_EUR0" class="cursorPointer numCuenta" onclick="kyos_irAMovsCuenta('ES9601824649840201502683','','EUR','','BANCO BILBAO VIZCAYA ARGENTARIA S.A','20199802','false','','VISONIC IBERICA DE SEGURIDAD S.L.');return false;">ES9601824649840201502683</a>
</td>
<td class=" columna1">
</tbody>
Example:
var _driver = new ChromeDriver();// or new IE()
_driver.Navigate().GoToUrl("https://www.tesst.com");
_driver.FindElement(By.Id(element)).Click();
//do what you need
_driver.Quit();
More proper way to do this is to set up unit tests, something like (Use resharper plugin to run tests):
[TestFixture]
class LoginTest
{
[TestFixtureSetUp]
public void FixtureSetup()
{
_driver = new ChromeDriver();
_driver.Navigate().GoToUrl("https://www.tesst.com");
}
[TestFixtureTearDown]
public void FixtureTearDown()
{
_driver.Quit();
}
[TestCase("kyos_enlaceIrAMovsCuenta_EUR0")]
public void PaywallClosedArticleCommertialTest(string element)
{
_driver.FindElement(By.Id(element)).Click();
//add assert
}
}
Try finding the element i.e., link in the T2 element which is parent
browser2.TableRow(Find.ById("kyos_filaCuenta_00")).Link(Find.ById("kyos_enlaceIrAMovsCuenta_EUR0")).Click();
I made a html grabber for a webbrowser in C#, but I am stuck.
The webpage looks like this:
<tbody class="first class"
<tc class="second class">
<td class=" ">abcdefg</td>
<td class=" ">1233456</td>
<td class=" ">qwertyo</td>
</tc>
I use this code to get the content of the three classes inside "second class":
HtmlElementCollection theElementCollection = default(HtmlElementCollection);
theElementCollection = webBrowser1.Document.GetElementsByTagName("tbody");
foreach (HtmlElement curElement in theElementCollection)
{
curElement.GetElementsByTagName("tc");
curElement.GetElementsByTagName("td");
label1.Text = curElement.GetAttribute("InnerText");
return;
}
The problem is that this stores ALL 3 contents in label1, so it looks like this:
abcdefg123456qwerto
Because the classes all have the same name, I can't grab only one content.
Is there a way to only grab the first content inside an element, so that it looks like this?
abcdefg
untested
HtmlDocument document = WebBrowser.Document;
if (document != null) {
HtmlElementCollection tableCollection = document.GetElementsByTagName("tbody");
foreach (HtmlElement table in tableCollection) {
HtmlElementCollection trColl = table.GetElementsByTagName("tc");
foreach (HtmlElement row in trColl) {
tds = row.GetElementsByTagName("td");
if (tds != null && tds.Count > 1) {
string neededText = tds[0].InnerText;
// 1.iteration: neededText == abcdefg
// 2.iteration: neededText == 123456
// 3.iteration: neededText == qwertyo
}
}
}
}
I am trying to highlight (around the border) element that is found in selenium webdriver using C#. I have search the net all i found was java codes, but need it in C#.
or is there any other way to do it.
thanks
There is no native way to do this, but because Selenium allows you use to execute Javascript, you can accomplish it just with a little more work:
Therefore the question becomes "how do I change an elements borders in Javascript?"
If you use jQuery it's a little bit easier, you could find the element and then set some border properties. jQuery has a neat little css property that allows you to pass in a JSON dictionary of values, it will handle setting them all for you, an example would be like:
jQuery('div.tagged > a:first').css({ "border-width" : "2px", "border-style" : "solid", "border-color" : "red" });
That would find an element, and set it's border to be solid at 2px wide with a border colour of red.
However, if you already have an IWebElement instance of the element (likely) you can take the 'finding' responsibility out of jQuery/Javascript and make it simpler again.
This would be executed something like:
var jsDriver = (IJavaScriptExecutor)driver;
var element = // some element you find;
string highlightJavascript = #"$(arguments[0]).css({ ""border-width"" : ""2px"", ""border-style"" : ""solid"", ""border-color"" : ""red"" });";
jsDriver.ExecuteScript(highlightJavascript, new object[] { element });
If you just want basic Javascript, then you could make use of the .cssText property, which allows you to give a full string of CSS styles instead of adding them individually (although I don't know how supported it is cross browser):
var jsDriver = (IJavaScriptExecutor)driver;
var element = // some element you find;
string highlightJavascript = #"arguments[0].style.cssText = ""border-width: 2px; border-style: solid; border-color: red"";";
jsDriver.ExecuteScript(highlightJavascript, new object[] { element });
(Although there are more ways, I've just gone for the most verbose to make it clearer)
C# Extension Method: Highlights and Clears in 3 seconds.
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Remote;
using System.Reactive.Linq;
public static class SeleniumUtil
{
public static void Highlight(this IWebElement context)
{
var rc = (RemoteWebElement)context;
var driver = (IJavaScriptExecutor)rc.WrappedDriver;
var script = #"arguments[0].style.cssText = ""border-width: 2px; border-style: solid; border-color: red""; ";
driver.ExecuteScript(script, rc);
Observable.Timer(new TimeSpan(0, 0, 3)).Subscribe(p =>
{
var clear = #"arguments[0].style.cssText = ""border-width: 0px; border-style: solid; border-color: red""; ";
driver.ExecuteScript(clear, rc);
});
}
}
Thanks Arran i just modified your answer..
var jsDriver = (IJavaScriptExecutor)driver;
var element = //element to be found
string highlightJavascript = #"arguments[0].style.cssText = ""border-width: 2px; border-style: solid; border-color: red"";";
jsDriver.ExecuteScript(highlightJavascript, new object[] { element });
it works perfectly...
thanks once again.
Write below JavaScript Executor code in your Class file
public void elementHighlight(WebElement element) {
for (int i = 0; i < 2; i++) {
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript(
"arguments[0].setAttribute('style', arguments[1]);",
element, "color: red; border: 5px solid red;");
js.executeScript(`enter code here`
"arguments[0].setAttribute('style', arguments[1]);",
element, "");
}
Call the above method from Selenium test case to highlight a web page element. Check out below code which shows how it is done. elementHighlight method is called with searchBox as an argument.
#Test
public void GoogleSearch() throws Exception, SQLException {
driver.findElement(By.xpath("//center/div[2]")).click();
WebElement searchBox = driver.findElement(By.xpath("//div[3]/div/input"));
elementHighlight(searchBox);
driver.findElement(By.xpath("//div[3]/div/input")).clear();
driver.findElement(By.xpath("//div[3]/div/input")).sendKeys("Test");
driver.findElement(By.xpath("//button")).click();
}
On executing the above test, Selenium test will highlight the search box on Google home page. You can reuse elementHighlight method for highlighting any elements on web page.