views:

284

answers:

1

I can't seem to find any documentation or code samples on how to add a hyperlink to a cell in Excel 2007 using the Open XML SDK 2.0. I am using the following code, but is there a step I am missing?

WorksheetPart workSheetPart = ExcelUtilities.GetWorkSheetPart(mWorkBookPart, "Program");

workSheetPart.AddHyperlinkRelationship(new Uri("http://www.google.com", UriKind.Absolute), true);

workSheetPart.Worksheet.Save();

mWorkBookPart.Workbook.Save();

Then when I try and open the Excel document it says the file is corrupted because the Relationship Id for the hyperlink cannot be found. How do you setup or create that Relationship Id?

+3  A: 

I was able to add a hyperlink to a cell using System.IO.Packaging code:

private void HyperlinkCreate(PackagePart part, XmlNamespaceManager nsm, XmlNode _cellElement, string CellAddress)
{
        Uri _hyperlink = new Uri("http://www.yahoo.com");
        XmlNode linkParent = _cellElement.OwnerDocument.SelectSingleNode("//d:hyperlinks", nsm);
        if (linkParent == null)
        {
            // create the hyperlinks node
            linkParent = _cellElement.OwnerDocument.CreateElement("hyperlinks", @"http://schemas.openxmlformats.org/spreadsheetml/2006/main");
            XmlNode prevNode = _cellElement.OwnerDocument.SelectSingleNode("//d:conditionalFormatting", nsm);
            if (prevNode == null)
            {
                prevNode = _cellElement.OwnerDocument.SelectSingleNode("//d:mergeCells", nsm);
                if (prevNode == null)
                {
                    prevNode = _cellElement.OwnerDocument.SelectSingleNode("//d:sheetData", nsm);
                }
            }
            _cellElement.OwnerDocument.DocumentElement.InsertAfter(linkParent, prevNode);
        }
        string searchString = string.Format("./d:hyperlink[@ref = '{0}']", CellAddress);
        XmlElement linkNode = (XmlElement)linkParent.SelectSingleNode(searchString, nsm);
        XmlAttribute attr;
        if (linkNode == null)
        {
            linkNode = _cellElement.OwnerDocument.CreateElement("hyperlink", @"http://schemas.openxmlformats.org/spreadsheetml/2006/main");
            // now add cell address attribute
            linkNode.SetAttribute("ref", CellAddress);
            linkParent.AppendChild(linkNode);
        }

        attr = (XmlAttribute)linkNode.Attributes.GetNamedItem("id", @"http://schemas.openxmlformats.org/officeDocument/2006/relationships");
        if (attr == null)
        {
            attr = _cellElement.OwnerDocument.CreateAttribute("r", "id", @"http://schemas.openxmlformats.org/officeDocument/2006/relationships");
            linkNode.Attributes.Append(attr);
        }                     

        PackageRelationship relationship = null;
        string relID = attr.Value;
        if (relID == "")
            relationship = part.CreateRelationship(_hyperlink, TargetMode.External, @"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink");
        else
        {
            relationship = part.GetRelationship(relID);
            if (relationship.TargetUri != _hyperlink)
                relationship = part.CreateRelationship(_hyperlink, TargetMode.External, @"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink");
        }
        attr.Value = relationship.Id;
}

I then translated this code using the Open XML SDK 2.0 and it doesn't work. It seems the AddHyperlinkRelationship method doesn't actually add the relationship to the .rels file. I'm not sure why, but it sure seems like a bug to me.

private void HyperlinkCreate(PackagePart part, XmlNamespaceManager nsm, XmlNode _cellElement, string CellAddress)
    {

WorksheetPart workSheetPart = ExcelUtilities.GetWorkSheetPart(mWorkBookPart, "Program");
            Uri hyperlinkUri = new Uri("http://www.yahoo.com", UriKind.Absolute);

            Hyperlinks hyperlinks = workSheetPart.Worksheet.Descendants<Hyperlinks>().FirstOrDefault();

            // Check to see if the <x:hyperlinks> element exists; if not figure out 
            // where to insert it depending on which elements are present in the Worksheet
            if (hyperlinks == null)
            {
                // Create the hyperlinks node
                hyperlinks = new Hyperlinks();

                OpenXmlCompositeElement prevElement = workSheetPart.Worksheet.Descendants<ConditionalFormatting>().FirstOrDefault();
                if (prevElement == null)
                {
                    prevElement = workSheetPart.Worksheet.Descendants<MergeCells>().FirstOrDefault();
                    if (prevElement == null)
                    {
                        // No FirstOrDefault needed since a Worksheet requires SheetData or the excel doc will be corrupt
                        prevElement = workSheetPart.Worksheet.Descendants<SheetData>().First();
                    }
                }
                workSheetPart.Worksheet.InsertAfter(hyperlinks, prevElement);
            }
            Hyperlink hyperlink = hyperlinks.Descendants<Hyperlink>().Where(r => r.Reference.Equals(CellAddress)).FirstOrDefault();
            if (hyperlink == null)
            {
                hyperlink = new Hyperlink() { Reference = CellAddress, Id = string.Empty };

            }

            HyperlinkRelationship hyperlinkRelationship = null;
            string relId = hyperlink.Id;
            if (relId.Equals(string.Empty))
            {
                hyperlinkRelationship = workSheetPart.AddHyperlinkRelationship(hyperlinkUri, true);
            }
            else
            {
                hyperlinkRelationship = workSheetPart.GetReferenceRelationship(relId) as HyperlinkRelationship;
                if (!hyperlinkRelationship.Uri.Equals(hyperlinkUri))
                {
                    hyperlinkRelationship = workSheetPart.AddHyperlinkRelationship(hyperlinkUri, true);
                }
            }
            hyperlink.Id = hyperlinkRelationship.Id;
            hyperlinks.AppendChild<Hyperlink>(hyperlink);
            workSheetPart.Worksheet.Save();     
        }
amurra