OpenXml - How to identify whether the paragraph extends to next page - openxml

From aspx page, I dynamically add paragraphs to a word document using OpenXml SDK. In this case, a page break within a paragraph is not allowed. So in case a paragraph starts in middle of page 1 and extends to page2 then it should actually start in Page2. However, if it ends in the same page it is okay.
How to achieve this? Is there a way to set in th document that page break is not allowed within a paragraph? Any input is highly appreciated.

In general you can not use the open xml sdk to determine where in a page an element will be displayed, since open xml has no concepts of pages.
Pages are determined by the client application consuming the open xml document. You can however specify that a paragraph's lines are kept together.
<w:p xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:pPr>
<w:keepLines />
</w:pPr>
<w:bookmarkStart w:name="_GoBack" w:id="0" />
<w:r>
<w:lastRenderedPageBreak />
<w:t>Most controls offer a choice of using the look from the current theme or using a format that you specify directly. To change the overall look of your document, choose new your document.</w:t>
</w:r>
<w:bookmarkEnd w:id="0" />
</w:p>
w:keepLines in the above examples paragraph properties is the key to making sure a paragraph is not split up between pages, below is the open xml required to generate the above paragrpah:
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml;
namespace GeneratedCode
{
public class GeneratedClass
{
// Creates an Paragraph instance and adds its children.
public Paragraph GenerateParagraph()
{
Paragraph paragraph1 = new Paragraph();
ParagraphProperties paragraphProperties1 = new ParagraphProperties();
KeepLines keepLines1 = new KeepLines();
paragraphProperties1.Append(keepLines1);
BookmarkStart bookmarkStart1 = new BookmarkStart(){ Name = "_GoBack", Id = "0" };
Run run1 = new Run();
LastRenderedPageBreak lastRenderedPageBreak1 = new LastRenderedPageBreak();
Text text1 = new Text();
text1.Text = "Most controls offer a choice of using the look from the current theme or using.";
run1.Append(lastRenderedPageBreak1);
run1.Append(text1);
BookmarkEnd bookmarkEnd1 = new BookmarkEnd(){ Id = "0" };
paragraph1.Append(paragraphProperties1);
paragraph1.Append(bookmarkStart1);
paragraph1.Append(run1);
paragraph1.Append(bookmarkEnd1);
return paragraph1;
}
}
}

Related

How can I add text to a document footer using OpenXML?

I have a document template that I want to append some text to the footer. I've seen ways of deleting the footer to replace it, and ways to replace text in the footer, but I want to keep the footer as is from the template and just add to it. I have code to add text to the main doc., but unfortunately, main doc. parts are not setup the same way as footer parts. This is easily accomplished in Interop by a range.InsertAfter(text), but end users need this to work sans Word.
FooterPart footer = _doc.MainDocumentPart.FooterParts.ElementAtOrDefault(0);
string rid = _doc.MainDocumentPart.GetIdOfPart(footer);
footer = _doc.MainDocumentPart.AddNewPart<FooterPart>(rid);
Paragraph para = footer.AddPart(new Paragraph(), rid);
Run run = para.AppendChild(new Run());
// get the last footer of the document
FooterPart footerPart = _doc.MainDocumentPart.FooterParts.LastOrDefault();
// create your paragraph. i created simple, but you will need to add style properties to the run or text class
Paragraph pr = new Paragraph(new Run(new Text("hello")));
// Insert the Paragraph to the end of the footer in footerPart.Footer
footerPart.Footer.AppendChild(pr);
Other way as you said would be putting a text to replace like "txttoreplace" and then you will find it and replace
IEnumerable<FooterPart> footerPartsList = Documento.MainDocumentPart.FooterParts.ToList();
foreach (FooterPart hp in footerPartsList)
foreach (Text text in hp.RootElement.Descendants<Text>())
{
if (text.Text.Contains("txttoreplace"))
{
text.Text = text.Text.Replace("txttoreplace", "new text");
}
}
And another way and the hardest would be, you inser the whole footer, with open xml productivity tools you get the c# code of the footer.xml, and then you delete the footer of the document and you insert.

How can I programmatically detect complex scipt using OOXML?

We are using Windward to generate reports in Microsoft Word.
Due to some update, Unicode Characters are no longer displaying properly.
While the vendor is still looking for a fix, we're looking for a work around.
One Symptom that I've noticed is that the "Normal" style does not appear in the "Styles Gallery" on the Ribbon.
I can find it in the "styles.xml" part of the file. I noticed that the style does not have a RSID associated with it, the way a normal MS Word file would.
GOOD FILE "Normal" style appears in Gallery
<w:style w:type="paragraph" w:styleId="Normal" w:default="1">
<w:name w:val="Normal" />
<w:qFormat />
<w:rsid w:val="003C4F1E" />
</w:style>
BAD FILE "Normal" style does NOT appear in Gallery
<w:style w:type="paragraph" w:default="1" w:styleId="Normal">
<w:name w:val="Normal"/>
</w:style>
Modifying the the Styles.xml file so that the "Normal" style would have rsid as well as qFormat xml tags fixed the issue of getting the "Normal" style to appear in the Gallery.
What I noticed was that once I had the "Normal" reappear and I clicked it without first having to select any text in the document, the Unicode Characters would display correctly.
When I checked document.xml I noticed that the following xml was added before the run:
<w:rPr>
<w:rFonts w:ascii="Mangal" w:hAnsi="Mangal" w:cs="Mangal"/>
</w:rPr>
How did MS Word know to select those values for the runPoperty?
How can I use ooxml to detect Complex script and then make the appropriate font selection?
SAMPLE XML USING COMPLEX SCRIPT
<w:r>
<w:rPr>
<w:rFonts w:ascii="Mangal" w:hAnsi="Mangal" w:cs="Mangal"/>
</w:rPr>
<w:t>एनडीटीवी</w:t>
</w:r>
What I have so far.
static bool GetRunText()
{
bool bStylesFound = false;
using (WordprocessingDocument doc = WordprocessingDocument.Open(_path, false))
{
// Get a reference to the main document part.
var docPart = doc.MainDocumentPart;
// Get the first paragraph.
Paragraph p = docPart.Document.Body.Descendants<Paragraph>().ElementAtOrDefault(0);
if (p == null)
{
Console.WriteLine("No paragraphs found.");
}
else
{
Run run = p.Descendants<Run>().ElementAtOrDefault(1);
RunProperties rp = run.RunProperties;
//Console.WriteLine(rp.RunFonts.);
bStylesFound = true;
}
return bStylesFound;
}
}

Creating a OOXML document with Track Changes enabled

How do I create a .docx with track changes enabled? I was told inside word/settings.xml I should modify w:proofState but all info in online docs of OOXML I find about that property is related to grammar and spell checking, but nothing about enabling tracking changes.
It is in word/settings.xml but the element you are looking for is w:trackRevisions.
To do this in C# using the OpenXML SDK you can use the TrackRevisions class. The following code will create a document with one paragraph and with change tracking turned on:
using (WordprocessingDocument package = WordprocessingDocument.Create(filename, WordprocessingDocumentType.Document))
{
// Add a new main document part.
package.AddMainDocumentPart();
//create a body and a paragraph
Body body = new Body();
Paragraph paragraph = new Paragraph();
paragraph.AppendChild(new Run(new Text("This document should have change tracking switched on")));
body.AppendChild(paragraph);
package.MainDocumentPart.Document = new Document(body);
//change tracking code
DocumentSettingsPart documentSettingsPart = package.MainDocumentPart.AddNewPart<DocumentSettingsPart>();
Settings settings = new Settings();
TrackRevisions trackRevisions = new TrackRevisions();
settings.Append(trackRevisions);
documentSettingsPart.Settings = settings;
// Save changes to the main document part.
package.MainDocumentPart.Document.Save();
}

iText(Sharp) - how to avoid creating a blank page?

I'm generating a PDF document using iTextSharp version 5.5.7, using their "streaming" mode - by which I mean I'm not specifying the location of every piece of text, I'm just adding Paragraphs to the Document and letting iTextSharp figure out where to draw them. The text I'm outputting is the result of a report generator, so it is different every time.
The problem I'm running into is this: imagine that, given the page size and the selected font, I can fit 40 lines of text on a page. I output 40 Paragraphs, then I output a blank Paragraph (contents=" "), then an image that fills an entire page. iTextSharp does exactly what I tell it - I end up with one page full of text, a blank page, and then a page containing my image.
But now my document looks funny - there is this unexpectedly blank page in the middle of everything.
I can't just say "don't output any blank lines" because of course that blank line might show up after only 20 lines of text, in which case it has to be there. I need some way to either tell iTextSharp "include this paragraph only if it's not the only thing on a page" or else somehow detect that the page is blank in OnEndPage() and suppress its output (without screwing up my page numbers).
Any suggestions on how I can do this?
ADDED LATER
Output from the report generator:
<html>
<p>Information header</p>
<p>Detail</p>
<p>Detail</p>
<p>Detail</p>
<p></p> <!-- Blank line inserted by report generator for clarity -->
<p>Information header</p>
<p>Detail</p>
<p>Detail</p>
<p>Detail</p>
...
<p>Detail</p> <!-- just by random happenstance this is the last line that will fit on the first page -->
<p></p> <!-- This line happens to be blank, I have no control over it -->
<img src="blah blah"></image>
My (pseudo) code:
foreach (HtmlNode node in htmlFromReportGenerator)
{
if (node is text)
pdfDoc.Add(new Paragraph(node.text));
else if (node is image)
pdfDoc.Add(new Image(node.image));
}
Following Bruno's suggestion, my (pseudo)code now looks like this:
Paragraph lastParagraph = null;
foreach (HtmlNode node in htmlFromReportGenerator)
{
if (node is text)
{
Paragraph parg = new Paragraph(node.text);
if ( (lastParagraph != null) && (text.Trim().Length == 0) )
lastParagraph.SpacingAfter += parg.Leading;
else
{
pdfDoc.Add(parg);
lastParagraph = parg;
}
}
else if (node is image)
{
pdfDoc.Add(new Image(node.image));
lastParagraph = null;
}
}

<path> created inside <svg> using GWT DOM class doesn't show up in the screen

I want to create a simple SVG graphics in GWT using only DOM manipulation (via DOM class). Eventually (after compilation with GWT compiler), I want to have a <path> element inside <svg> element.
The final effect should look, more or less, as follows:
<html>
<body>
<svg>
<path stroke="black" d="M200 200 L300 150"></path>
</svg>
</body>
</html>
Here is the java GWT code which should create such effect:
Element svg = DOM.createElement("svg");
Document.get().getBody().appendChild(svg);
Element path = DOM.createElement("path");
path.setAttribute("stroke", "black");
path.setAttribute("d", "M200 200 L300 150");
svg.appendChild(path);
The problem is that the path doesn't show up in the browser (I can see only white background). What's very interesting, if I see the source of the page via the browser, copy the whole source (from <html> to </html>), paste it to a new blank document in a text editor, save it to the hard drive as HTML file and open it in the browser, the path is displayed (it means the source is updated correctly).
Why the path doesn't show up in the screen for the first time (and does show up for the second time)?
Thank you for your help!
Edit:
As it turns out, using ComplexPanel and XML namespace works if I want to draw a <path> element. But now I want to draw a text along path.
The final effect should look like this:
<svg>
<defs>
<path id="myPath" stroke="black" d="M75,20 a1,1 0 0,0 100,0"></path>
</defs>
<text x="10" y="100">
<textPath xlink:href="#myPath">Text along a curved path...</textPath>
</text>
</svg>
The java code which should generate it:
class SVGPanel extends ComplexPanel {
private static final String SVG_NAMESPACE = "http://www.w3.org/2000/svg";
public SVGPanel() {
setElement(createElementNS(SVG_NAMESPACE, "svg"));
showcaseSVG();
}
private void showcaseSVG() {
Element defs = createElementNS(SVG_NAMESPACE, "defs");
getElement().appendChild(defs);
Element path = createElementNS(SVG_NAMESPACE, "path");
path.setAttribute("id", "myPath");
path.setAttribute("stroke", "black");
path.setAttribute("d", "M75,20 a1,1 0 0,0 100,0");
defs.appendChild(path);
Element text = createElementNS(SVG_NAMESPACE, "text");
text.setAttribute("x", "10");
text.setAttribute("y", "100");
getElement().appendChild(text);
Element textPath = createElementNS(SVG_NAMESPACE, "textPath");
textPath.setAttribute("xlink:href", "#myPath");
textPath.setInnerText("Text along a curved path...");
text.appendChild(textPath);
}
private native Element createElementNS(final String ns,
final String name)/*-{
return document.createElementNS(ns, name);
}-*/;
}
The text along path doesn't show up. Of course, as previously, if I copy the generated source to a new HTML file and open it in the browser, it does.
I think you need to use setAttributeNS, passing in the xlink namespace.
So in the given code above, replace:
textPath.setAttribute("xlink:href", "#myPath");
With:
textPath.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", "#myPath");
Well the problem seems to be that there is no namespace defined for the svg. Also svgs seem to only be drawn in GWT if they are set in a ComplexPanel....
Anyway here is a example how to draw a SVG element with GWT.
package XXXXXXX;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.ComplexPanel;
public class SVGPanel extends ComplexPanel {
private static final String SVG_NAMESPACE = "http://www.w3.org/2000/svg";
public SVGPanel() {
setElement(createElementNS(SVG_NAMESPACE, "svg"));
showcaseSVG(); // Demonstrate that SVG works! Inexplicably!
}
private void showcaseSVG() {
Element svgElement = createElementNS(SVG_NAMESPACE, "circle");
svgElement.setAttribute("cx", "50");
svgElement.setAttribute("cy", "50");
svgElement.setAttribute("r", "30");
getElement().appendChild(svgElement);
}
private static native Element createElementNS(final String ns,
final String name)/*-{
return document.createElementNS(ns, name);
}-*/;
}
Adding this to your rootpanel draws the specified path.
Sources: http://de.w3support.net/index.php?db=so&id=691809
Regards,
Stefan