3

我正在使用库修改.docx文档。DocumentFormat.OpenXml我知道元素排序很重要,否则文档将无法通过架构验证,并可能导致无法在 Word 中打开的文档。

现在我需要DocumentProtectionDocumentSettingsPart. 我需要将这个子元素插入到父元素的正确位置。

架构如下所示:

OpenXML 模式

子元素有很多可能的顺序。目前我正在添加这样的元素:

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使其符合模式并且不涉及枚举所有可能的元素?

4

1 回答 1

4

没有一个很好的方法来实现你想要的。您将不得不修补集合,并且您有责任保持订单正确。

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

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

设置分机

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;
}
            
于 2016-03-26T17:07:49.413 回答