How to get list from docx file? - openxml

How to determine whether a list is bulleted or numbered? I use OpenXML
In general, what will be the list determines NumberingDefinitionsPart, I thought to find out the Numbering of a certain element, but this method did not work
I am processing the list in the recommended way, but I need to know which way it is
`public void ParagraphHandle(Elements.Paragraph paragraph, StringBuilder text)
{
var docPart = paragraph.DocumentPart;
var element = paragraph.Element;
var r = element.Descendants<Numbering>().ToArray();
var images = GetImages(docPart, element);
if (images.Count > 0)
{
foreach (var image in images)
{
if (image.Id != null)
{
string filePath = _saveResources.SaveImage(image);
_handler.ImageHandle(filePath, text);
}
}
return;
}
var paragraphProperties = element.GetFirstChild<ParagraphProperties>();
var numberingProperties = paragraphProperties?.GetFirstChild<NumberingProperties>();
if (numberingProperties != null)
{
var numberingId = numberingProperties.GetFirstChild<NumberingId>()?.Val?.Value;
if (numberingId != null && !paragraph.IsList)
{
text.AppendLine("<ul>");
paragraph.IsList = true;
paragraph.List = new List();
_htmlGenerator.GenerateList(paragraph, text);
}
else
{
_htmlGenerator.GenerateList(paragraph, text);
}
}
else
{
if (paragraph.IsList)
{
text.AppendLine("</ul>");
paragraph.IsList = false;
}
_handler.ParagraphHandle(element, text);
}
}`

Related

I am getting multiple headers and footers in word document, getting null in policy.GetFirstPageHeader() using NPOI

I am getting multiple headers and footers in a Word document; I cannot differentiate the firstpage, default(odd), or even headers.
When I am trying to call policy.GetFirstPageHeader() I am getting a null value.
XWPFHeaderFooterPolicy policy = new XWPFHeaderFooterPolicy(document);
var headerList = document.HeaderList;
var footerList = document.FooterList;
var firstPageHeader = policy.GetFirstPageHeader();
var firstPageFooter = policy.GetFirstPageFooter();
XWPFHeader header = policy.GetDefaultHeader();
XWPFHeader even = policy.GetEvenPageHeader();
XWPFHeader odd = policy.GetOddPageHeader();
I am getting null values. Can any one suggest how to differentiate headers in a Word document?
var listOfheaders = new List<CT_HdrFtrRef>();
foreach (var par in document.Paragraphs)
{
var ParagraphsectPr = (CT_P)par.GetType().GetField("paragraph", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(par);
if (ParagraphsectPr.pPr.sectPr != null)
{
foreach (var headerref in ParagraphsectPr.pPr.sectPr.headerReference)
{
listOfheaders.Add(headerref);
}
}
}
foreach (var list in listOfheaders)
{
var relatedPart = document.GetRelationById(list.id);
XWPFHeader hdr = null;
if (relatedPart != null && relatedPart is XWPFHeader)
{
hdr = (XWPFHeader)relatedPart;
}
// Assign it
ST_HdrFtr type = list.type;
if (!string.IsNullOrEmpty(hdr.Text))
{
if (type == ST_HdrFtr.first)
{
firstPageHeadr = hdr;
}
else if (type == ST_HdrFtr.even)
{
evenPageHeader = hdr;
}
else
{
defaultHeader = hdr;
}
}
}

Fill Picture content control in header of word doc using OpenXML

I want to fill my Picture Content Control which is located in the header of my word document with this code: (I have passed content control tag and the image stream via document parameter to this function)
public void FillDocument(Stream stream, XDocument document)
{
using (WordprocessingDocument wordDocument =
WordprocessingDocument.Open(stream, true))
{
List<SdtElement> descendants = wordDocument.MainDocumentPart.Document.Descendants<SdtElement>().ToList();
foreach (var headerPart in wordDocument.MainDocumentPart.HeaderParts)
{
descendants.AddRange(headerPart.Header.Descendants<SdtElement>().ToList());
}
foreach (var footerPart in wordDocument.MainDocumentPart.FooterParts)
{
descendants.AddRange(footerPart.Footer.Descendants<SdtElement>().ToList());
}
XDocument doc = document;
foreach (SdtElement item in descendants)
{
SdtAlias alias = item.Descendants<SdtAlias>().FirstOrDefault();
if (alias != null)
{
string sdtTitle = alias.Val.Value;
//if Sdt Content Control is Picture
string imageContent = (from xElement in doc.Descendants("Picture") where xElement.Attribute("Id").Value == sdtTitle select xElement.Value).FirstOrDefault();
if (imageContent != null)
{
MemoryStream result = (MemoryStream)StringToStream(imageContent);
SdtProperties p = item.Elements<SdtProperties>().FirstOrDefault();
if (p != null)
{
// Is it a picture content control?
SdtContentPicture pict = p.Elements<SdtContentPicture>().FirstOrDefault();
// Get the alias.
SdtAlias a = p.Elements<SdtAlias>().FirstOrDefault();
if (pict != null && a.Val.Value == sdtTitle)
{
string embed = null;
Drawing dr = item.Descendants<Drawing>().FirstOrDefault();
if (dr != null)
{
D.Blip blip = dr.Descendants<D.Blip>().FirstOrDefault();
if (blip != null)
embed = blip.Embed;
if (embed != null)
{
IdPartPair idpp = wordDocument.MainDocumentPart.Parts
.Where(pa => pa.RelationshipId == embed).FirstOrDefault();
if (idpp != null)
{
ImagePart ip = (ImagePart)idpp.OpenXmlPart;
ip.FeedData(result);
}
}
}
}
}
continue;
}
}
}
It finds the content control in word document but in this line:
ImagePart ip = (ImagePart)idpp.OpenXmlPart;
I get this error:
Unable to cast object of type
‘DocumentFormat.OpenXml.Packaging.CustomXmlPart’ to type
‘DocumentFormat.OpenXml.Packaging.ImagePart’.
Could you please guide me?
I tried to find a way, here is the answer:
public void FillDocument(Stream stream, XDocument document)
{
using (WordprocessingDocument wordDocument =
WordprocessingDocument.Open(stream, true))
{
List<SdtElement> descendants = wordDocument.MainDocumentPart.Document.Descendants<SdtElement>().ToList();
foreach (HeaderPart headerPart in wordDocument.MainDocumentPart.HeaderParts)
{
descendants.AddRange(headerPart.Header.Descendants<SdtElement>().ToList());
}
foreach (var footerPart in wordDocument.MainDocumentPart.FooterParts)
{
descendants.AddRange(footerPart.Footer.Descendants<SdtElement>().ToList());
}
XDocument doc = document;
foreach (SdtElement item in descendants)
{
SdtAlias alias = item.Descendants<SdtAlias>().FirstOrDefault();
if (alias != null)
{
string sdtTitle = alias.Val.Value;
//if Sdt Content Control is Picture
string imageContent = (from xElement in doc.Descendants("Picture") where xElement.Attribute("Id").Value == sdtTitle select xElement.Value).FirstOrDefault();
if (imageContent != null)
{
MemoryStream result = (MemoryStream)StringToStream(imageContent);
D.Blip blipElement = item.Descendants<D.Blip>().FirstOrDefault();
string imageId = "default value";
if (blipElement != null)
{
imageId = blipElement.Embed.Value;
ImagePartType imagePartType = ImagePartType.Png;
//Add image and change embeded id.
ImagePart imagePart = null;
Type p = item.Parent.GetType();
switch (p.Name)
{
case "Header":
HeaderPart headerPart = ((Header)(item.Parent)).HeaderPart;
imagePart = headerPart.AddImagePart(imagePartType);
imagePart.FeedData(result);
blipElement.Embed = headerPart.GetIdOfPart(imagePart);
break;
case "Body":
MainDocumentPart mainDocumentPart = wordDocument.MainDocumentPart;
imagePart = mainDocumentPart.AddImagePart(imagePartType);
imagePart.FeedData(result);
blipElement.Embed = mainDocumentPart.GetIdOfPart(imagePart);
break;
case "Footer":
FooterPart footerPart = ((Footer)(item.Parent)).FooterPart;
imagePart = footerPart.AddImagePart(imagePartType);
imagePart.FeedData(result);
blipElement.Embed = footerPart.GetIdOfPart(imagePart);
break;
default:
break;
}
}
continue;
}
}
}
}}
It works fine and can fill the picture content control in header or footer or body!

E4X to JSON conversion fails for duplicate xml elements

Kindly see below code I am using to convert Mirth xml to JSON.
function E4XtoJSON(xml, ignored) {
var r, children = xml.*, attributes = xml.#*, length = children.length();
if(length == 0) {
r = xml.toString();
} else if(length == 1) {
var text = xml.text().toString();
if(text) {
r = text;
}
}
if(r == undefined) {
r = {};
for each (var child in children) {
var name = child.localName();
var json = E4XtoJSON(child, ignored);
var value = r[name];
if(value) {
if(value.length) {
value.push(json);
} else {
r[name] = [value, json]
}
} else {
r[name] = json;
}
}
}
if(attributes.length()) {
var a = {}, c = 0;
for each (var attribute in attributes) {
var name = attribute.localName();
if(ignored && ignored.indexOf(name) == -1) {
a["_" + name] = attribute.toString();
c ++;
}
}
if(c) {
if(r) a._ = r;
return a;
}
}
return r;
}
My concern is
<AdditionalMessageInformationCount AdditionalMessageInformationCount="02"><AdditionalMessageInformationQualifier>01</AdditionalMessageInformationQualifier><AdditionalMessageInformation>MEMBER MUST USE MAIL ORDER.</AdditionalMessageInformation><AdditionalMessageInformationQualifier>02</AdditionalMessageInformationQualifier><AdditionalMessageInformation>PLAN LIMITATIONS EXCEEDED</AdditionalMessageInformation></AdditionalMessageInformationCount>
Here AdditionalMessageInformation elemt is used two times so function fails to create JSON.
Kindly help if anyone have converted XML in json usingg javascript code not any API
We've had success with this version:
function E4XtoJSON(xml, ignored){
var r, children = xml.*,
attributes = xml.# * ,
length = children.length();
if (length == 0)
{
r = xml.toString();
}
else if (length == 1)
{
var text = xml.text().toString();
if (text)
{
r = text;
}
}
if (r == undefined)
{
r = {};
for each(var child in children)
{
var name = child.localName();
var json = E4XtoJSON(child, ignored);
var value = r[name];
if (value)
{
if (value instanceof Array)
{
value.push(json);
}
else
{
r[name] = [value, json]
}
}
else
{
r[name] = json;
}
}
}
if (attributes.length())
{
var a = {},
c = 0;
for each(var attribute in attributes)
{
var name = attribute.localName();
if (ignored && ignored.indexOf(name) == -1)
{
a["_" + name] = attribute.toString();
c++;
}
}
if (c)
{
if (r) a._ = r;
return a;
}
}
return r;
}
With the release of Mirth Connect version 3.3.0, you can use Mirth Connect to set your channel's interior data type to JSON. This will all be done for you.

Replace bookmark contents in Word using OpenXml

I can't find any working code examples for replacing bookmark contents. The code should be able to handle both the case replace empty bookmark and replace bookmark with preexisting content.
For example: If I have this text in a Word document:
"Between the following periods comes Bookmark1.. Between next periods comes Bookmark2.."
and I want to insert the text "BM1" between the first periods, and "BM2" between the next.
After the first replacement run, the replacements are inserted correctly.
But after the next replacement run, all of the text on the line after Bookmark1 gets deleted, and then the replacement for Bookmark2 gets inserted.
This is my c# code:
var doc = WordprocessingDocument.Open(#"file.docx", true);
public static Dictionary<string, wd.BookmarkStart> FindAllBookmarksInWordFile(WordprocessingDocument file)
{
var bookmarkMap = new Dictionary<String, wd.BookmarkStart>();
foreach (var headerPart in file.MainDocumentPart.HeaderParts)
{
foreach (var bookmarkStart in headerPart.RootElement.Descendants<wd.BookmarkStart>())
{
if (!bookmarkStart.Name.ToString().StartsWith("_"))
bookmarkMap[bookmarkStart.Name] = bookmarkStart;
}
}
foreach (var bookmarkStart in file.MainDocumentPart.RootElement.Descendants<wd.BookmarkStart>())
{
if (!bookmarkStart.Name.ToString().StartsWith("_"))
bookmarkMap[bookmarkStart.Name] = bookmarkStart;
}
return bookmarkMap;
}
/*extension methods*/
public static bool IsEndBookmark(this OpenXmlElement element, BookmarkStart startBookmark)
{
return IsEndBookmark(element as BookmarkEnd, startBookmark);
}
public static bool IsEndBookmark(this BookmarkEnd endBookmark, BookmarkStart startBookmark)
{
if (endBookmark == null)
return false;
return endBookmark.Id.Value == startBookmark.Id.Value;
}
/* end of extension methods */
public static void SetText(BookmarkStart bookmark, string value)
{
RemoveAllTexts(bookmark);
bookmark.Parent.InsertAfter(new Run(new Text(value)), bookmark);
}
private static void RemoveAllTexts(BookmarkStart bookmark)
{
if (bookmark.ColumnFirst != null) return;
var nextSibling = bookmark.NextSibling();
while (nextSibling != null)
{
if (nextSibling.IsEndBookmark(bookmark) || nextSibling.GetType() == typeof(BookmarkStart))
break;
foreach (var item in nextSibling.Descendants<Text>())
{
item.Remove();
}
nextSibling = nextSibling.NextSibling();
}
}
I have looked around a long time for a general solution.
Any help is appreciated! -Victor
Maybe this can help you
first:delete bookmarkContent
second:find bookMark => insert value
public static void InsertTest1(WordprocessingDocument doc, string bookMark, string txt)
{
try
{
RemoveBookMarkContent(doc, bookMark);
MainDocumentPart mainPart = doc.MainDocumentPart;
BookmarkStart bmStart = findBookMarkStart(doc, bookMark);
if (bmStart == null)
{
return;
}
Run run = new Run(new Text(txt));
bmStart.Parent.InsertAfter<Run>(run, bmStart);
}
catch (Exception c)
{
//not Exception
}
}
public static void RemoveBookMarkContent(WordprocessingDocument doc, string bmName)
{
BookmarkStart bmStart = findBookMarkStart(doc, bmName);
BookmarkEnd bmEnd = findBookMarkEnd(doc, bmStart.Id);
while (true)
{
var run = bmStart.NextSibling();
if (run == null)
{
break;
}
if (run is BookmarkEnd && (BookmarkEnd)run == bmEnd)
{
break;
}
run.Remove();
}
}
private static BookmarkStart findBookMarkStart(WordprocessingDocument doc, string bmName)
{
foreach (var footer in doc.MainDocumentPart.FooterParts)
{
foreach (var inst in footer.Footer.Descendants<BookmarkStart>())
{
if (inst.Name == bmName)
{
return inst;
}
}
}
foreach (var header in doc.MainDocumentPart.HeaderParts)
{
foreach (var inst in header.Header.Descendants<BookmarkStart>())
{
if (inst.Name == bmName)
{
return inst;
}
}
}
foreach (var inst in doc.MainDocumentPart.RootElement.Descendants<BookmarkStart>())
{
if (inst is BookmarkStart)
{
if (inst.Name == bmName)
{
return inst;
}
}
}
return null;
}
This code works but not when the bookmark is placed within a field/formtext (a gray box).
private static void SetNewContents(wd.BookmarkStart bookmarkStart, string text)
{
if (bookmarkStart.ColumnFirst != null) return;
var itemsToRemove = new List<OpenXmlElement>();
var nextSibling = bookmarkStart.NextSibling();
while (nextSibling != null)
{
if (IsEndBookmark(nextSibling, bookmarkStart))
break;
if (nextSibling is wd.Run)
itemsToRemove.Add(nextSibling);
nextSibling = nextSibling.NextSibling();
}
foreach (var item in itemsToRemove)
{
item.RemoveAllChildren();
item.Remove();
}
bookmarkStart.Parent.InsertAfter(new wd.Run(new wd.Text(text)), bookmarkStart);
}

How to calculate the color based on given fgColor indexed

I am working on Open XML,
<x:fill>
<x:patternFill patternType="solid">
<x:fgColor indexed="46" />
<x:bgColor indexed="64" />
</x:patternFill>
</x:fill>
Above is a office 2007 document that converted from office 2003.
According to http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.foregroundcolor.aspx
Indexed attributes only used for backward compatibility purposes.
Above is my code, how to calculate the #Hex Color Code for indexed = 46?
I made this class for myself. Hope I save someone some trouble
public class IndexedColours
{
static Dictionary<string, string> Data;
IndexedColours()
{
if(Data == null || Data.Count == 0)
{
Data = new Dictionary<string, string>();
Data.Add("0", "000000");
Data.Add("1", "FFFFFF");
Data.Add("2", "FF0000");
Data.Add("3", "00FF00");
Data.Add("4", "0000FF");
Data.Add("5", "FFFF00");
Data.Add("6", "FF00FF");
Data.Add("7", "00FFFF");
Data.Add("8", "000000");
Data.Add("9", "FFFFFF");
Data.Add("10", "FF0000");
Data.Add("11", "00FF00");
Data.Add("12", "0000FF");
Data.Add("13", "FFFF00");
Data.Add("14", "FF00FF");
Data.Add("15", "00FFFF");
Data.Add("16", "800000");
Data.Add("17", "008000");
Data.Add("18", "000080");
Data.Add("19", "808000");
Data.Add("20", "800080");
Data.Add("21", "008080");
Data.Add("22", "C0C0C0");
Data.Add("23", "808080");
Data.Add("24", "9999FF");
Data.Add("25", "993366");
Data.Add("26", "FFFFCC");
Data.Add("27", "CCFFFF");
Data.Add("28", "660066");
Data.Add("29", "FF8080");
Data.Add("30", "0066CC");
Data.Add("31", "CCCCFF");
Data.Add("32", "000080");
Data.Add("33", "FF00FF");
Data.Add("34", "FFFF00");
Data.Add("35", "00FFFF");
Data.Add("36", "800080");
Data.Add("37", "800000");
Data.Add("38", "008080");
Data.Add("39", "0000FF");
Data.Add("40", "00CCFF");
Data.Add("41", "CCFFFF");
Data.Add("42", "CCFFCC");
Data.Add("43", "FFFF99");
Data.Add("44", "99CCFF");
Data.Add("45", "FF99CC");
Data.Add("46", "CC99FF");
Data.Add("47", "FFCC99");
Data.Add("48", "3366FF");
Data.Add("49", "33CCCC");
Data.Add("50", "99CC00");
Data.Add("51", "FFCC00");
Data.Add("52", "FF9900");
Data.Add("53", "FF6600");
Data.Add("54", "666699");
Data.Add("55", "969696");
Data.Add("56", "003366");
Data.Add("57", "339966");
Data.Add("58", "003300");
Data.Add("59", "333300");
Data.Add("60", "993300");
Data.Add("61", "993366");
Data.Add("62", "333399");
Data.Add("63", "333333");
}
}
public static string GetIndexColour(string Index)
{
var d = new IndexedColours();
var res = "";
var exist = Data.TryGetValue(Index, out res);
if (exist)
return res;
else return "000000";
}
}
Method to use the above code:
public static string GetCellColour(this Cell cell, SpreadsheetDocument d)
{
if (cell != null && cell.StyleIndex != null)
{
var valcell = cell;
var styles = d.WorkbookPart.WorkbookStylesPart;
var ss = styles.Stylesheet;
var formats = ss.CellFormats;
var cf = (CellFormat)formats.ElementAt((int)valcell.StyleIndex.Value);
var fill = (Fill)styles.Stylesheet.Fills.ChildElements[(int)cf.FillId.Value];
var fgc = fill.PatternFill.ForegroundColor;
var cl = fgc == null || fgc.Rgb == null ? "FFFFFF" : fgc.Rgb.Value.Remove(0, 2);
if (fgc != null && fgc.Indexed != null && fgc.Indexed.HasValue)
{
cl = IndexedColours.GetIndexColour(fgc.Indexed.Value.ToString());
}
return cl;
}
else return "FFFFFF";
}
Solved my problem, there is color indexes online. just search for it.