none
Selecting and replacing CustomXmlBlocks and CustomXmlRuns (...in a performant way) RRS feed

  • Question

  • Hello everyone!

    my current implementation of an document generation application depends on Office 2003 XML.
    In the basic template Custom XML is used both for business sematic purposes in my smartdocument solution
    and as placeholder. Depended on the provided paramters some placeholder (Custom XML Elements) are replaced
    by other ones from other components.

    The application is currently implmented for Office 2003 XML. There I can easly replace these placholder using an
    XSLT transforamtion, since content like pictures are base64encoded within the markup.

    Now I have to migrate this solution to Office 2007. May be some of you can help me with the following questions:
    - Is there an easy and performant way to select all CustomXmlRuns and CustomXmlBlocks?
    - How can ich I replace e.g. the CustomXmlBlocks when containing an Image and threfore referencing an image 
      part in my package?

    In order to select the all the CustomXmlBlocks and Runs I wrote the following code - by seems to me not very performant?
    Do you have a better solution?

    By the way, up to now i haven't found a good way to replace the matching CustomXmlElements. Usually i'm getting the following error:
    "Can not replace the OpenXmlElement "newChild" because it is part of a tree."
    I understand why that it a problem, but since the insert method throws the same exception, i do not know how to perform such an replacement.

    /// <summary>  
    /// Replace the CustomXMLBlocks and CustomXmlRuns from the provided parant ChildElements (recursive)  
    /// </summary>  
    /// <param name="dictionary">Dictionary containing all CustomXMLBlocks and CustomXmlRuns with their element name, which will be used as replacements</param>  
    /// <param name="parent">OpenXmlNode, which children have to be filtered recursively</param>  
    private static void ReplaceTemplateCustomXmlElements(Dictionary<string,OpenXmlElement> dictionary, OpenXmlElement parent)  
    {  
        if (dictionary == null)  
            throw new ArgumentException(ErrorWarningException.InternalErrorNoList);  
     
        if (!parent.HasChildren)  
            return;  
     
        var list = new List<OpenXmlElement>();  
     
        foreach (var child in parent.ChildElements)  
        {  
            //Ignore Non-CustomXmlBlocks // text   
            if (child is CustomXmlBlock || child is CustomXmlRun)  
            {  
                var childAttributes = child.GetAttributes();  
                foreach (var childattribute in childAttributes)  
                {  
                    if (childattribute.LocalName == "uri" && childattribute.Value == NANESPACE_OF_MY_ELEMENTS)  
                    {  
                        //later we only want to replace CustomXmlElements matching our Namespace  
                        list.Add(child);  
                    }  
                }  
            }  
     
            if (child.HasChildren)  
                ReplaceTemplateCustomXmlElements(dictionary, child);  
     
        }  
     
        //iterate all found direct child nodes and replace them  
        foreach (var element in list)  
        {  
                        string attributename =  
                            element.GetAttribute("element",  
                                               "http://schemas.openxmlformats.org/wordprocessingml/2006/main").Value;  
     
            //TODO: Thsi does not work and throw the exception:  
            //Can not replace/insert the OpenXmlElement "newChild" because it is part of a tree.  
            parent.ReplaceChild(dictionary[attributename], element);  
        }  
    }  
     


    Thanks a lot,
    Thomas
    • Edited by Thomas C.F_ Tuesday, October 21, 2008 10:21 PM Provided updated Code and added further information about the problem - recursive replacement
    Tuesday, October 21, 2008 10:32 AM

All replies

  • Hi Thomas,

    Have you tried OpenXmlElement.Descendants<CustomXmlRun>?

    Invoke that on the custom xml root element, and you'll get IEnumerator<CustomXmlRun>.
    xinxing
    Wednesday, November 5, 2008 9:26 AM