Avatar billede casjachan Nybegynder
07. oktober 2004 - 10:15 Der er 8 kommentarer og
1 løsning

Merge, sammenflette to xml filer til ny xml fil

Situationen er som følger:

Jeg har to xml dokumenter, doc1.xml og doc2.xml. doc1.xml er et reference dokument, dvs at jeg vil have doc2.xml til at være en tro kopi af doc1.xml. Dette betyder at der for hver node, element, attribut i doc1.xml skal tjekkes om det samme står i doc2.xml. Dette gælder også kommentarer. Hvis linien allerede eksisterer i doc2.xml skal den ikke overskrives, ellers skal den tilføjes doc2.xml i den rigtige sektion. Det indhold som er i doc2.xml som ikke optræder i referencedokumentet doc1.xml, skal ignoreres og blive stående i doc2.xml. Det samlede dokument bliver så samlet.xml.

eks:

doc1.xml:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="key0" value="0" />
      <add key="key1" value="1" />
      <add key="key2" value="2" />
  </appSettings>
</configuration>

doc2.xml:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="key0" value="22" />
      <add key="key1" value="22" />
    <add key="key532" value="54" />
  </appSettings>
</configuration>

samlet.xml:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="key0" value="22" />
      <add key="key1" value="22" />
      <add key="key2" value="2" />
    <add key="key532" value="54" />
  </appSettings>
</configuration>
Avatar billede jakobandersen Nybegynder
07. oktober 2004 - 10:51 #1
Du kan forholdsvis let merge de to dokumenter ved brug af XSLT, men problemet kommer med kommentarerne.
Avatar billede arne_v Ekspert
07. oktober 2004 - 11:10 #2
Hvis keys altid kommer i sorteret rækkefølge, så er det nærmest en klassisk
læs fra to filer og skriv til en fil opgave, hvor man bare skal læse og skrive
XML.

Hvis keys ikke kommer i sorteret rækkefølge, så er det lidt mere besværligt, da
man skal søge efter tingene.

Du bliver nødt til at præcisere hvordan kommentarer skal håndteres. Da det
ikke er helt entydigt hvordan de hænger sammen med add key'erne. Hænger en
kommentar sammen med den næste add key eller med den forrige add key.
Avatar billede casjachan Nybegynder
07. oktober 2004 - 11:19 #3
ideen er at referencefilen doc1.xml indeholder de nøgler der er nødvendige og disse nøgler står i en bestemt rækkefølge, eventuelt med kommentarer før nøglen. Dokumentet doc2.xml skal valideres op mod doc1.xml, og have den samme opbygning som doc1.xml, hvis dette ikke er tilfældet fra starten. Dette betyder at doc2.xml til slut vil have samme keys, samme kommentarer, samme opbygning, men ikke nødvendigvis samme value for de enkelte keys. Kommentarer er ikke så vigtigt i første omgang. På denne måde slipper man får at tjekke om alle keys er i doc2.xml, men sørge for at dokumentet ligner doc1.xml. Er der keys i doc2.xml som ikke er i doc1.xml, skal disse blot blive i doc2.xml.
Avatar billede casjachan Nybegynder
07. oktober 2004 - 14:00 #4
Jeg har løst problemet med at tage hver enkel node i referencedokumentet og tjekke om den eksisterer i det dokument der skal tjekkes. Resten må komme hen ad vejen.
Avatar billede jakobandersen Nybegynder
07. oktober 2004 - 14:18 #5
Jeg har lige bikset et stylesheet sammen der gør det du ønsker(bortset fra kommentarerne som det ikke lader til at parseren sender med til XSLT Transformeren):

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml"/>

<xsl:variable name="OldappSettings" select="document('doc1.xml')/configuration/appSettings/add"/>
<xsl:variable name="NewappSettings" select="document('doc2.xml')/configuration/appSettings/add"/>

<xsl:template match="/">
    <configuration>
        <appSettings>
           
            <xsl:for-each select="$NewappSettings">
                <add key="{@key}" value="{@value}" />
            </xsl:for-each>
           
            <xsl:for-each select="$OldappSettings">
                <xsl:variable name="currentkey" select="@key" />
                <xsl:if test="count($NewappSettings[@key = $currentkey]) = 0">
                    <add key="{@key}" value="{@value}" />
                </xsl:if>
            </xsl:for-each>
        </appSettings>
    </configuration>
</xsl:template>
</xsl:stylesheet>

Hvis kommentarerne kommer med til XSLT skulle de kunne fanges ved at tilføje:

<xsl:template match="comment()">
  <xsl:comment><xsl:value-of select="."/></xsl:comment>
</xsl:template>

Ovenstående er snippet fra: http://www.xml.com/pub/a/2000/09/13/xslt/
Avatar billede casjachan Nybegynder
07. oktober 2004 - 15:30 #6
Hvis jakobandersen lige vil poste et svar, får du 100 point for din anstrengelse
Avatar billede jakobandersen Nybegynder
07. oktober 2004 - 15:40 #7
Jeg kom lige i tanke om noget XSLT kode jeg engang så til at slå to filer sammen, det kan du evt. også lige kigge på:

http://www.informatik.hu-berlin.de/~obecker/XSLT/#merge
Avatar billede jakobandersen Nybegynder
07. oktober 2004 - 15:41 #8
Og ovenstående er implementeret i C# her:
http://weblogs.asp.net/cazzu/archive/2003/11/20/38885.aspx
Avatar billede arne_v Ekspert
09. oktober 2004 - 01:21 #9
Her er en kode version som også håndterer kommentarer:

using System;
using System.Collections;
using System.Text;
using System.Xml;

public class KeyValue
{
    private string comm;
    private string key;
    private string val;
    public KeyValue(string comm, string key, string val)
    {
        this.comm = comm;
        this.key = key;
        this.val = val;
    }
    public string Comm
    {
        get
        {
            return comm;
        }
        set
        {
            comm = value;
        }
    }
    public string Key
    {
        get
        {
            return key;
        }
        set
        {
            key = value;
        }
    }
    public string Val
    {
        get
        {
            return val;
        }
        set
        {
            val = value;
        }
    }
}

public class Merger
{
    private Hashtable lookup;
    private ArrayList store;
    private string lastcomment;
    public Merger()
    {
        lookup = new Hashtable();
        store = new ArrayList();
    }
    private void Process(XmlNode node)
    {
        if(node.NodeType == XmlNodeType.Element && node.Name == "add")
        {
            string k = node.Attributes["key"].Value;
            string v = node.Attributes["value"].Value;
            KeyValue kv = (KeyValue)lookup[k];
            if(kv != null)
            {
                kv.Val = v;
            }
            else
            {
                kv = new KeyValue(lastcomment, k, v);
                store.Add(kv);
                lookup.Add(k, kv);
            }
        }
        foreach(XmlNode n in node.ChildNodes)
        {
            Process(n);
        }
        if(node.NodeType == XmlNodeType.Comment)
        {
            lastcomment = node.Value;
        }
        else
        {
            lastcomment = null;
        }
    }
    private void Load(string filename)
    {
        XmlDocument doc = new XmlDocument();
        doc.Load(filename);
        Process(doc.DocumentElement);
    }
    public void Combine(string masterdoc, string doc)
    {
        Load(masterdoc);
        Load(doc);
    }
    public void Save(string newdoc)
    {
        XmlTextWriter wrt = new XmlTextWriter(newdoc, Encoding.UTF8);
        wrt.Formatting = Formatting.Indented;
        wrt.Indentation = 4;
        wrt.WriteStartDocument();
        wrt.WriteStartElement("configuration");
        wrt.WriteStartElement("appSettings");
        foreach(KeyValue kv in store)
        {
            if(kv.Comm != null)
            {
                wrt.WriteComment(kv.Comm);
            }
            wrt.WriteStartElement("add");
            wrt.WriteAttributeString("key", kv.Key);
            wrt.WriteAttributeString("value", kv.Val);
            wrt.WriteEndElement();
        }
        wrt.WriteEndElement();
        wrt.WriteEndElement();
        wrt.WriteEndDocument();
        wrt.Close();
    }
}

class TestClass
{
    public static void Main(string[] args)
    {
        Merger merg = new Merger();
        merg.Combine(@"C:\doc1.xml", @"C:\doc2.xml");
        merg.Save(@"C:\newdoc2.xml");
    }
}
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester