Как сохранить форматирование стиля при объединении двух документов ODT

Я работаю с библиотекой AODL для C#. До сих пор я смог импортировать текст второго документа в первый. Проблема в том, что я не могу понять, что мне нужно, чтобы убедиться, что стиль также перенесен в объединенный документ. Ниже приведен простой код, который я использую для тестирования. Самый близкий ответ, который я могу найти, - это слияние двух файлов.odt из кода, что несколько отвечает на мой вопрос, но все равно не говорит мне, где мне нужно поместить стиль / где его получить. Это, по крайней мере, дает мне понять, что мне нужно пройтись по стилям во втором документе и убедиться, что в первом не совпадают имена, иначе будут конфликты. Я не уверен, что именно делать, и документация была очень скудной. Прежде чем вы предложите что-нибудь, я хотел бы сообщить вам, что да, odt - это тип файла, с которым мне нужно работать, и выполнение любых взаимодействий, как Microsoft делает с Word, не то, что мне нужно. Если есть еще одна библиотека, которая работает так же, как AODL, я все уши.

TextDocument mergeTemplateDoc = ReadContentsOfFile(mergeTemplateFileName);
TextDocument vehicleTemplateDoc = ReadContentsOfFile(vehicleTemplateFileName);

foreach (IContent piece in vehicleTemplateDoc.Content)
{
    XmlNode newNode = mergeTemplateDoc.XmlDoc.ImportNode(piece.Node,true);

    Paragraph p = ParagraphBuilder.CreateParagraphWithExistingNode(mergeTemplateDoc, newNode);

    mergeTemplateDoc.Content.Add(p);
}

mergeTemplateDoc.SaveTo("MergComplete.odt");

2 ответа

Решение

Вот что я сделал, чтобы решить мою проблему. Имейте в виду, что с тех пор, как был задан этот вопрос, я перешел на использование Java, поскольку библиотека на этом языке работает немного лучше.

По сути, методы, описанные ниже, это захват автоматических стилей, сгенерированных в каждом документе. Он просматривает второй документ и находит каждый узел стиля, проверяя атрибут name. Это имя затем помечается дополнительным идентификатором, который уникален для этого документа, поэтому, когда они объединяются, они не конфликтуют между собой.

MergeFontTypesToPrimaryDoc просто захватывает шрифты, которые еще не существуют в первичном документе, так как на все шрифты ссылаются одинаково в документах, редактирование которых не требуется.

UpdateNodeChildrenStyleNames - это просто рекурсивный метод, который я использовал, чтобы убедиться, что я обновляю все узлы в стиле линии, чтобы удалить любые конфликтующие имена между двумя документами.

Эта похожая идея должна работать и в C#.

private static void mergeStylesToPrimaryDoc(OdfTextDocument primaryDoc, OdfTextDocument secondaryDoc) throws Exception {
    OdfFileDom primaryContentDom = primaryDoc.getContentDom();
    OdfOfficeAutomaticStyles primaryDocAutomaticStyles = primaryDoc.getContentDom().getAutomaticStyles();
    OdfOfficeAutomaticStyles secondaryDocAutomaticStyles = secondaryDoc.getContentDom().getAutomaticStyles();
    //Adopt style nodes from secondary doc
    for(int i =0; i<secondaryDocAutomaticStyles.getLength();i++){
        Node style = secondaryDocAutomaticStyles.item(i).cloneNode(true);
        if(style.hasAttributes()){
            NamedNodeMap attributes = style.getAttributes();
            for(int j=0; j< attributes.getLength();j++){
                Node a = attributes.item(j);
                if(a.getLocalName().equals("name")){
                    a.setNodeValue(a.getNodeValue()+_stringToAddToStyle);
                }
            }
        }
        if(style.hasChildNodes()){
            updateNodeChildrenStyleNames(style, _stringToAddToStyle, "name");
        }


        primaryDocAutomaticStyles.appendChild(primaryContentDom.adoptNode(style));

    }
}

private static void mergeFontTypesToPrimaryDoc(OdfTextDocument primaryDoc, OdfTextDocument secondaryDoc) throws Exception {
    //Insert referenced font types that are not in the primary document you are merging into
    NodeList sdDomNodes = secondaryDoc.getContentDom().getChildNodes().item(0).getChildNodes();
    NodeList pdDomNodes = primaryDoc.getContentDom().getChildNodes().item(0).getChildNodes();
    OdfFileDom primaryContentDom = primaryDoc.getContentDom();
    Node sdFontNode=null;
    Node pdFontNode=null;
    for(int i =0; i<sdDomNodes.getLength();i++){
        if(sdDomNodes.item(i).getNodeName().equals("office:font-face-decls")){
            sdFontNode = sdDomNodes.item(i);
            break;
        }
    }
    for(int i =0; i<pdDomNodes.getLength();i++){
        Node n =pdDomNodes.item(i); 
        if(n.getNodeName().equals("office:font-face-decls")){
            pdFontNode = pdDomNodes.item(i);
            break;
        }
    }
    if(sdFontNode !=null && pdFontNode != null){
        NodeList sdFontNodeChildList = sdFontNode.getChildNodes();
        NodeList pdFontNodeChildList = pdFontNode.getChildNodes();
        List<String> fontNames = new ArrayList<String>();
        //Get list of existing fonts in primary doc
        for(int i=0; i<pdFontNodeChildList.getLength();i++){
            NamedNodeMap attributes = pdFontNodeChildList.item(i).getAttributes(); 
            for(int j=0; j<attributes.getLength();j++){
                if(attributes.item(j).getLocalName().equals("name")){
                    fontNames.add(attributes.item(j).getNodeValue());
                }
            }
        }
        //Check each font in the secondary doc to make sure it gets added if the primary doesn't have it
        for(int i=0; i<sdFontNodeChildList.getLength();i++){
            Node fontNode = sdFontNodeChildList.item(i).cloneNode(true); 
            NamedNodeMap attributes = fontNode.getAttributes();
            String fontName="";
            for(int j=0; j< attributes.getLength();j++){
                if(attributes.item(j).getLocalName().equals("name")){
                    fontName = attributes.item(j).getNodeValue();
                    break;
                }
            }
            if(!fontName.equals("") && !fontNames.contains(fontName)){
                pdFontNode.appendChild(primaryContentDom.adoptNode(fontNode));
            }

        }
    }
}

private static void updateNodeChildrenStyleNames(Node n, String stringToAddToStyle, String nodeLocalName){
    NodeList childNodes = n.getChildNodes();
    for (int i=0; i< childNodes.getLength(); i++){

        Node currentChild = childNodes.item(i);

        if(currentChild.hasAttributes()){
            NamedNodeMap attributes = currentChild.getAttributes();
            for(int j =0; j < attributes.getLength(); j++){
                Node a = attributes.item(j);
                if(a.getLocalName().equals(nodeLocalName)){
                    a.setNodeValue(a.getNodeValue() + stringToAddToStyle);
                }
            }
        }
        if(currentChild.hasChildNodes()){
            updateNodeChildrenStyleNames(currentChild, stringToAddToStyle, nodeLocalName);
        }
    }
} 

}

Я не знаю, насколько точно это должно быть закодировано, но с помощью 7zip я смог просто скопировать весь файл styles.xml из одного файла в другой. Программно это должно быть так же просто. Я всегда форматирую свои файлы стилями, а не прямым форматированием. Так что простая замена любого файла склонна к устранению локальных стилей.

Я нашел этот ответ (на вопрос "Очистка таблицы стилей от неиспользуемых стилей") https://www.mobileread.com/forums/showpost.php?s=cbbee08a1204df71ec5cd88bcf222253&p=2100914&postcount=13 который просматривает все стили в одном документе. Это не показывает, как включить одно в другое, но основа ясна.

'---------------------------------------------------------- 03/02/2012
' Supprimer les styles personnalisés inutilisés
' d'un document texte ou d'un classeur
'---------------------------------------------------------------------
sub stylesPersoInutiles()
dim coStylesFamilles as object, oStyleFamille as object
dim oStyle as object, nomFamille as string
dim f as long, x as long
dim ts(), buf as string, iRet as integer
const SEP = ", "

    coStylesFamilles = thisComponent.StyleFamilies
    for f = 0 to coStylesFamilles.count -1
        ' Pour chaque famille
        nomFamille = coStylesFamilles.elementNames(f)
        oStyleFamille = coStylesFamilles.getByName(nomFamille)
        buf = ""
        for x = 0 to oStyleFamille.Count -1
            ' Pour chaque style
            oStyle = oStyleFamille(x)
            'xray oStyle            
            if (oStyle.isUserDefined) and (not oStyle.isInUse) then
                buf = buf & oStyle.name & SEP
            end if
        next x

        if len(buf) > len(SEP) then
            buf = left(buf, len(buf) - len(SEP))
            iRet = msgBox("Styles personnalisés non utilisés : " _
                & chr(13) & buf & chr(13) & chr(13) _
                & "Faut-il les détruire ?", 4+32+256, nomFamille)
            if iRet = 6 then
                ts = split(buf, SEP)
                for x = 0 to uBound(ts) 
                    oStyleFamille.removeByName(ts(x))
                next x
            end if
        end if
    next f
end sub
Другие вопросы по тегам