How can I use Custom Xml / User-Defined Tags in .p

2019-08-25 11:20发布

问题:

I need to embed custom data in a .pptx that I generate, so that it can later be uploaded and have the images in the doc updated by my code.

I've tried a couple of methods now, and done lots of looking. I've found a couple of answers quite similar to this, but their solutions haven't worked for me - though perhaps I've just implemented them wrong. (links at the bottom)

The methods I've tried are:

1) Storing the custom data in an ExtendedAttribute:

//OpenXmlDrawing = DocumentFormat.OpenXml.Drawing

// there's only one image per slide for now, so I just grab the blip which contains the image
OpenXmlDrawing.Blip blip = slidePart.Slide.Descendants<OpenXmlDrawing.Blip>().FirstOrDefault(); 

//then apply the attribute
blip.SetAttribute(new OpenXmlAttribute("customAttributeName", null, customAttributeValue));

Doing so, the custom attributes would be wiped as soon as "Enable Editing" was turned on in PowerPoint 2013.

2) Store data in a a CustomXmlPart - this seems to be the generally agreed upon method from a few other posts.

So pretty much this is where I've ended up after multiple variations on this method:

public class CustomPropertyClass
{
    public string Id { get; set; }
    public string PropertyName { get; set; }
    public string PropertyValue { get; set; }
}

private static void AddCustomPropertyToPart(string propertyName, string propertyValue, SlidePart slidePart, PresentationPart presentationPart)
{

    var rId = GenerateNewRelationshipIdForPart(presentationPart);
    CustomXmlPart customXmlPart = slidePart.AddNewPart<CustomXmlPart>("application/xml", rId);
    var customPropertyObject = new CustomPropertyClass { Id = rId, PropertyName = propertyName, PropertyValue = propertyValue };

    // serialize wwXmlProperty object & write that xml to the CustomXmlPart
    var serializer = new System.Xml.Serialization.XmlSerializer(customPropertyObject.GetType());
    var stream = new MemoryStream();
    serializer.Serialize(stream, customPropertyObject);

    var customXml = System.Text.Encoding.UTF8.GetString(stream.ToArray());
    using (var streamWriter = new StreamWriter(customXmlPart.GetStream()))
    {
        streamWriter.Write(customXml);
        streamWriter.Flush();
    }

    // write CustomXmlElement into commonSlideData

    OpenXmlElement openXmlCustomElement;
    using (StreamWriter sw = new StreamWriter(new MemoryStream()))
    {
        sw.Write(customXml);
        sw.Flush();
        sw.BaseStream.Seek(0, SeekOrigin.Begin);

        OpenXmlReader re = OpenXmlReader.Create(sw.BaseStream);

        re.Read();
        openXmlCustomElement = re.LoadCurrentElement();
        re.Close();
    }

    Slide slide = slidePart.Slide;
    var commonSlideData = slide.GetFirstChild<CommonSlideData>();
    var commonSlideDataExtensionList = commonSlideData.GetFirstChild<CommonSlideDataExtensionList>();
    commonSlideData.InsertBefore(openXmlCustomElement, commonSlideDataExtensionList);
}

It seems like it is being preserved through the 'Enable Editing' being turned on now. However as soon as I actually make an edit and save it, the changes are gone.

I'm using OpenXmlSDK 2.5 Productivity Tool to confirm the xml is in there or not. Here's an example of the presentation with the custom xml in it:

As you can see, there's also a CustomXml item10.xml a couple levels higher. That also disappears as soon as changes are saved.


Links to other similar issues:

Why does my custom XML not carry over to a new version of a DOCX file when Word saves it?

http://openxmldeveloper.org/archive/2010/10/26/59361.aspx

https://social.msdn.microsoft.com/Forums/office/en-US/f1683cbe-d662-465a-978b-36277bb476e5/powerpoint-deletes-relation-of-customxmlpart-to-slide?forum=oxmlsdk

https://github.com/OfficeDev/Open-XML-SDK/issues/127


EDIT: I've now also tried using UserDefinedTags:

private static void AddCustomPropertyToPart(string propertyName, string propertyValue, SlidePart slidePart, PresentationPart presentationPart)
{

    var rId = GenerateNewRelationshipIdForPart(presentationPart);

    TagList tagList = new TagList();
    Tag tag = new Tag() { Name = propertyName, Val = propertyValue };

    tagList.Append(tag);

    var userTagsPart = slidePart.AddNewPart<UserDefinedTagsPart>(rId);

    userTagsPart.TagList = tagList;
}

Which added the tags appropriately, but when I saved the presentation, once again they were gone.

I also tried using running a VBA Macro to add the tags to the base report template:

Sub AssignSlidesChartToolTypes()

    Dim ChartToolType As String

    For i = 1 To Application.ActivePresentation.Slides.Count

        With Application.ActivePresentation.Slides(i)
            ChartToolType = InputBox("Enter Chart Tool Type for Slide " & i)

            With .Tags
                .Add "chartToolType", ChartToolType
            End With
        End With
    Next

End Sub

To use these, I had to save it as a .pptm file, but even then, they aren't preserved after making edits.