1

I am having trouble updating a Hyperlink in a Word doc (Q How to update the body and a hyperlink in a Word doc ) and am zooming in on the Descendants<T>() call not working. Here is my code:

using DocumentFormat.OpenXml.Packaging;      //from NuGet ClosedXML
using DocumentFormat.OpenXml.Wordprocessing; //from NuGet ClosedXML

WordprocessingDocument doc = WordprocessingDocument.Open(...filename..., true);
MainDocumentPart mainPart = doc.MainDocumentPart;
IEnumerable<Hyperlink> hLinks = mainPart.Document.Body.Descendants<Hyperlink>();

The doc is opened OK because mainPart gets a value. But hLinks has no elements. If I open the Word doc in Word, a hyperlink is present and working.

In the Immediate Window I see the following values:

mainPart.Document.Body
-->
{DocumentFormat.OpenXml.Wordprocessing.Body}
    ChildElements: {DocumentFormat.OpenXml.OpenXmlChildElements}
    ExtendedAttributes: {DocumentFormat.OpenXml.EmptyEnumerable<DocumentFormat.OpenXml.OpenXmlAttribute>}
    FirstChild: {DocumentFormat.OpenXml.OpenXmlUnknownElement}
    HasAttributes: false
    HasChildren: true
    InnerText: "
       lots of data, e.g:
    ...<w:t>100</w:t>...

mainPart.Document.Body.Descendants<Text>().First()
-->
Exception: "Sequence contains no elements"

If I cannot even find the text parts, how should I ever find and replace the hyperlink?

Roland
  • 4,619
  • 7
  • 49
  • 81
  • 1
    Mmm, the code in the question works for me - I copied and pasted that line. – Cindy Meister Jan 24 '19 at 18:07
  • @CindyMeister I added some more test output in the question. It shows as FirstChild an `OpenXmlUnknownElement`, is that something to worry about? Is that different from the test you did? – Roland Jan 25 '19 at 10:57

2 Answers2

1

If you are sure there are elements in your file that you are searching with linq, and nothing is returning or you are getting exceptions, that typically points to a namespace problem.

If you post your entire file, I can better help you, but check to see if you can alias your namespace like so:

using W = DocumentFormat.OpenXml.Wordprocessing;

and then in your Descendants call you do something like this:

var hLinks = mainPart.Document.Body.Descendants<W.Hyperlink>();

This answer demonstrates another namespace trick to try also.

Taterhead
  • 5,763
  • 4
  • 31
  • 40
  • Great namespace tip, but this is not the solution. Hovering the mouse over Hyperlink or Descendants, the namespace is shown. Also, using the Goto Definition feature in VisualStudio, leads to the correct library. After adding both of your source code lines, the W in the second one shows as grey, meaning that it is redundant and results in the same namespace as without the `W.` prefix. So I will upvote but not accept your answer. – Roland Jan 25 '19 at 10:37
  • OK - well if you can post a minimal solution and data file where we can reproduce it, I am confident we can troubleshoot it and get to the bottom of the problem. Often times you will find the solution as you develop a minimal solution. Please see: https://stackoverflow.com/help/mcve – Taterhead Jan 25 '19 at 10:58
0

Something seems to be wrong with my Word doc; it was generated with a tool. Testing with another Word doc, created with Word, gives better results. I am working on it ...

With a regular Word doc, looking at

doc.MainDocumentPart.Document.Body.InnerXml

the value starts with:

<w:p w:rsidR=\"00455325\" w:rsidRDefault=\"00341915\" 
  xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">
  <w:r>
    <w:t>Hello World!

but with the word doc I am testing with, which comes from a tool I myself made:

<w:body xmlns:w=\"http://schemas.openxmlforma...

This explains a lot. I will have to fix my tool :-)


Update:

The fix was that this did not give the correct part of data to insert in the Word Doc:

string strDocumentXml = newWordContent.DocumentElement.InnerXml;

but instead this is the correct data:

string strDocumentXml = newWordContent.DocumentElement.FirstChild.OuterXml;

Inspection with the debugger of:

doc.MainDocumentPart.Document.Body.InnerXml

as mentioned above, confirmed it. The Descendants call now returns the expected data, and updating the hyperlink works.


Side note:

I clearly fixed a bug in my app, but, apart from updating the hyperlink, the app worked perfectly OK before, with that bug :-)

Roland
  • 4,619
  • 7
  • 49
  • 81