其他分享
首页 > 其他分享> > 使用OpenXML时,按正确的顺序插入子元素

使用OpenXML时,按正确的顺序插入子元素

作者:互联网

我正在使用DocumentFormat.OpenXml库修改.docx文档.我知道element ordering is important,否则文档将无法通过架构验证,并且可能会导致无法在Word中打开文档.

现在,我需要向DocumentSettingsPart中添加一个DocumentProtection元素.我需要将此子元素插入到父元素的正确位置.

模式如下所示:

OpenXML Schema

子元素有很多可能的排序.目前,我正在像这样添加此元素:

var documentProtection = new DocumentProtection()
{
    // do the configuration
};

DocumentSettingsPart settings = doc.MainDocumentPart.DocumentSettingsPart;
var rootElement = settings.RootElement;
var prevElement = 
                rootElement.GetFirstChild<DoNotTrackFormatting>() ??
                rootElement.GetFirstChild<DoNotTrackMoves>() ??
                rootElement.GetFirstChild<TrackRevisions>() ??
                rootElement.GetFirstChild<RevisionView>() ??
                rootElement.GetFirstChild<DocumentType>() ??
                rootElement.GetFirstChild<StylePaneSortMethods>() ??
                // SNIP
                rootElement.GetFirstChild<Zoom>() ??
                rootElement.GetFirstChild<View>() ??
                (OpenXmlLeafElement)rootElement.GetFirstChild<WriteProtection>();
rootElement.InsertAfter(documentProtection, prevElement);

即我试图找到在我的文档中是否应该存在任何可能的元素.然后在该元素之后插入DocumentProtection.在给定元素数量的情况下,该列表变得非常无聊.

有没有更好的方法来添加DocumentProtection,使其符合架构且不涉及所有可能元素的枚举?

解决方法:

没有什么好方法可以实现您想要的.您必须修改产品系列,并负责确保订单正确无误.

Settings类上使用ILSpy,您会发现实现者使用了辅助方法SetElement< T>.在需要位置和要插入实例的基类上.

不幸的是,该辅助方法标记为内部方法,因此如果您尝试将“设置”子类化,我们将无法利用它.相反,我重新实现了所需的功能,因此您将拥有Settings的子类,该子类的确提供了DocumentProtection的属性,但使用了重新实现的解决方案来找到插入节点的正确位置:

设置Ext

public class SettingsExt: Settings
{
    // contruct based on XML
    public SettingsExt(string outerXml)
        :base(outerXml)
    {
        // empty
    }

    public DocumentProtection DocumentProtection
    {
        // get is easy
        get
        {
            return this.GetFirstChild<DocumentProtection>();
        }
        // reimplemented SetElement based on 
        // reversed engineered Settings class
        set
        {

            // eleTagNames is a static string[] declared later
            // it holds all the names of the elements in the right order
            int sequenceNumber = eleTagNames
                .Select((s, i) => new { s= s, idx = i })
                    .Where(s => s.s == "documentProtection")
                    .Select((s) => s.idx)
                    .First(); 
            OpenXmlElement openXmlElement = this.FirstChild;

            OpenXmlElement refChild = null;
            while (openXmlElement != null)
            {
                // a bit naive
                int currentSequence = eleTagNames
                    .Select((s, i) => new { s = s, idx = i })
                    .Where(s => s.s == openXmlElement.LocalName)
                    .Select((s) => s.idx)
                    .First(); ; 
                if (currentSequence == sequenceNumber)
                {
                    if (openXmlElement is DocumentProtection)
                    {
                        refChild = openXmlElement.PreviousSibling();
                        this.RemoveChild<OpenXmlElement>(openXmlElement);
                        break;
                    }
                    refChild = openXmlElement;
                }
                else
                {
                    if (currentSequence > sequenceNumber)
                    {
                        break;
                    }
                    refChild = openXmlElement;
                }
                openXmlElement = openXmlElement.NextSibling();
            }
            if (value != null)
            {
                this.InsertAfter(value, refChild);
            }
        }
    }

    // order of elements in the sequence!
    static readonly string[] eleTagNames = new string[]
    {
        "writeProtection",
        "view",
        "zoom",
        "removePersonalInformation",
        "removeDateAndTime",
        "doNotDisplayPageBoundaries",
        "displayBackgroundShape",
        "printPostScriptOverText",
        "printFractionalCharacterWidth",
        "printFormsData",
        "embedTrueTypeFonts",
        "embedSystemFonts",
        "saveSubsetFonts",
        "saveFormsData",
        "mirrorMargins",
        "alignBordersAndEdges",
        "bordersDoNotSurroundHeader",
        "bordersDoNotSurroundFooter",
        "gutterAtTop",
        "hideSpellingErrors",
        "hideGrammaticalErrors",
        "activeWritingStyle",
        "proofState",
        "formsDesign",
        "attachedTemplate",
        "linkStyles",
        "stylePaneFormatFilter",
        "stylePaneSortMethod",
        "documentType",
        "mailMerge",
        "revisionView",
        "trackRevisions",
        "doNotTrackMoves",
        "doNotTrackFormatting",
        "documentProtection",
        "autoFormatOverride",
        "styleLockTheme",
        "styleLockQFSet",
        "defaultTabStop",
        "autoHyphenation",
        "consecutiveHyphenLimit",
        "hyphenationZone",
        "doNotHyphenateCaps",
        "showEnvelope",
        "summaryLength",
        "clickAndTypeStyle",
        "defaultTableStyle",
        "evenAndOddHeaders",
        "bookFoldRevPrinting",
        "bookFoldPrinting",
        "bookFoldPrintingSheets",
        "drawingGridHorizontalSpacing",
        "drawingGridVerticalSpacing",
        "displayHorizontalDrawingGridEvery",
        "displayVerticalDrawingGridEvery",
        "doNotUseMarginsForDrawingGridOrigin",
        "drawingGridHorizontalOrigin",
        "drawingGridVerticalOrigin",
        "doNotShadeFormData",
        "noPunctuationKerning",
        "characterSpacingControl",
        "printTwoOnOne",
        "strictFirstAndLastChars",
        "noLineBreaksAfter",
        "noLineBreaksBefore",
        "savePreviewPicture",
        "doNotValidateAgainstSchema",
        "saveInvalidXml",
        "ignoreMixedContent",
        "alwaysShowPlaceholderText",
        "doNotDemarcateInvalidXml",
        "saveXmlDataOnly",
        "useXSLTWhenSaving",
        "saveThroughXslt",
        "showXMLTags",
        "alwaysMergeEmptyNamespace",
        "updateFields",
        "hdrShapeDefaults",
        "footnotePr",
        "endnotePr",
        "compat",
        "docVars",
        "rsids",
        "mathPr",
        "uiCompat97To2003",
        "attachedSchema",
        "themeFontLang",
        "clrSchemeMapping",
        "doNotIncludeSubdocsInStats",
        "doNotAutoCompressPictures",
        "forceUpgrade",
        "captions",
        "readModeInkLockDown",
        "smartTagType",
        "schemaLibrary",
        "shapeDefaults",
        "doNotEmbedSmartTags",
        "decimalSymbol",
        "listSeparator",
        "docId",
        "discardImageEditingData",
        "defaultImageDpi",
        "conflictMode"};

}

此类的典型使用场景如下:

using (var doc = WordprocessingDocument.Open(@"c:\tmp\test.docx", true))
{

    var documentProtection = new DocumentProtection()
    {
        Formatting = DocumentFormat.OpenXml.OnOffValue.FromBoolean(true)
    };

    DocumentSettingsPart settings = doc.MainDocumentPart.DocumentSettingsPart;

    // instantiate our ExtendedSettings class based on the
    // original Settings
    var extset = new SettingsExt(settings.Settings.OuterXml);

    // new or existing?
    if (extset.DocumentProtection == null)
    {
        extset.DocumentProtection = documentProtection;
    }
    else
    {
        // replace existing values
    }

    // this is key to make sure our own DOMTree is saved!
    // don't forget this
    settings.Settings = extset;
}

标签:xsd,system-xml,xml,c,openxml-sdk
来源: https://codeday.me/bug/20191119/2032565.html