Avatar billede CodingJoe Nybegynder
04. februar 2011 - 13:35 Der er 12 kommentarer og
1 løsning

Manipulering af XmlDocument

Jeg vil gerne tilføje et namespace til et eksiterende xml document.
Hvordan gør jeg det?

Jeg har følgende udseende af et XmlDocument:
<?xml version="1.0" encoding="utf-16"?>
<MyRoot>
  <A>tekst</A>
  <B>323700</B>
  <C>11</C>
  <D>4</D>
</MyRoot>

Jeg vil gerne få det til at få dette udseende:

<n1:MyRoot xmlns:n1="http://foo.crap.foo.crap">
  <A>tekst</A>
  <B>323700</B>
  <C>11</C>
  <D>4</D>
</n1:MyRoot>

Det skal lige siges at jeg serialisere inden jeg har et XmlDocument, det kan være jeg kan få mit namespace ind på en anden måde. Dog har jeg prøvet, og får følgende:

<n1:MyRoot xmlns:n1="http://foo.crap.foo.crap">
  <n1:A>tekst</n1:A>
  <n1:B>323700</n1:B>
  <n1:C>11</n1:C>
  <n1:D>4</n1:D>
</n1:MyRoot>

...og her er det min kode går i stykker, da mit skema ikke kan validere min xml.

Er der noget, jeg kan gøre?
Avatar billede arne_v Ekspert
04. februar 2011 - 16:37 #1
Jeg er lidt skeptisk overfor jvorvodt du virkelig vil have den midterste form.

Men anyway til inspiration:

using System;
using System.Xml;

namespace Feb2
{
    public class Program
    {
        public static void SetNS(XmlNode n, string prefix, string nsurl, bool recurse)
        {
            if(n.NodeType == XmlNodeType.Element)
            {
                XmlElement oldelm = (XmlElement)n;
                XmlElement newelm = oldelm.OwnerDocument.CreateElement(prefix, oldelm.LocalName, nsurl);
                oldelm.ParentNode.ReplaceChild(newelm, oldelm);
                while(oldelm.HasChildNodes)
                {
                    newelm.AppendChild(oldelm.RemoveChild(oldelm.FirstChild));
                    if(recurse)
                    {
                        SetNS(newelm.LastChild, prefix, nsurl, recurse);
                    }
                }
            }
        }
        public static void Main(string[] args)
        {
            string s = @"<MyRoot>
  <A>tekst</A>
  <B>323700</B>
  <C>11</C>
  <D>4</D>
</MyRoot>";
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(s);
            doc.Save(Console.Out);
            SetNS(doc.DocumentElement, "ns1", "http://foobar", false);
            doc.Save(Console.Out);
            SetNS(doc.DocumentElement, "ns1", "http://foobar", true);
            doc.Save(Console.Out);
            Console.ReadKey();
        }
    }
}
Avatar billede CodingJoe Nybegynder
04. februar 2011 - 16:59 #2
Hej Arne

Det kan være mit skema er problemet. Jeg har spekuleret meget over, hvilken måde er mest korrekt.

Lige nu gør jeg dette og det ser ud til a fungere:
var e = xml.DocumentElement;
if (e != null) e.SetAttribute("xmlns:ns1","http://foobar");
Avatar billede CodingJoe Nybegynder
04. februar 2011 - 17:05 #3
Kan jeg ikke sætte en decorator tingest på min klasse, som jeg serialiserer så jeg får en:

<n1:MyRoot xmlns:n1="http://foo.crap.foo.crap"> ud?

min klasse hedder MyRoot.
Avatar billede CodingJoe Nybegynder
04. februar 2011 - 17:41 #4
Jeg fik dog et problem med at sætte et prefix på mit rod element:

Forsøgte at manipulere med mit xml doc med følgende:
XmlElement e = xml.DocumentElement;
if (e != null) e.SetAttribute("xmlns:ns2", "http://foo.crap.foo.crap");
xml.DocumentElement.Prefix = "ns2";

men der skete ingenting med rod elementet. Jeg kan se du laver en save, men det er jo fysiske filer...hvordan persisterer jeg prefikset in memory?
Avatar billede arne_v Ekspert
04. februar 2011 - 17:47 #5
doc.Save(Console.Out);

er kun for at se effekten af ændringen.
Avatar billede CodingJoe Nybegynder
04. februar 2011 - 17:51 #6
ja, så dvs. at min linje der:
xml.DocumentElement.Prefix = "ns2";

burde prefikse mit rod element?
Avatar billede arne_v Ekspert
04. februar 2011 - 18:58 #7
Det er noget rod at forsøge manuelt at sætte en namespace attribut. Namespaces er ikke almindelige attributter.

Mit forslag er at gøre det rigtigt.
Avatar billede CodingJoe Nybegynder
04. februar 2011 - 19:09 #8
Det rigtige ville jo være at sætte namespacet på min klasse som jeg serialiserer...
Der må være en decorator ting, som jeg kan sætte i toppen af min klasse.

Lidt á la:
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://foo.crap.foo.crap", IsNullable = true)]
public class MyClass {
  public string A {get; set;}
  public decimal B {get; set;}
}

problemet er bare at xmlns:ns1 kommer ikke som et prefiks på mit rod-element ej heller bliver det sat ind i 'xmlns:ns1'.

Ellers skal mit skema kunne validere formatet:
<n1:MyRoot xmlns:n1="http://foo.crap.foo.crap">
  <n1:A>tekst</n1:A>
  <n1:B>323700</n1:B>
  <n1:C>11</n1:C>
  <n1:D>4</n1:D>
</n1:MyRoot>

hvori alle elementerne får det prefiks.
Avatar billede CodingJoe Nybegynder
04. februar 2011 - 19:15 #9
Den måde jeg kunne få namespacet ind på, var ved at sætte det på programmatisk:

var namespaces = new XmlSerializerNamespaces();
namespaces.Add("ns1", "http://foo.crap.foo.crap");

og bagefter serialisere mit objekt med namespaces som argument:

var serializer = new XmlSerializer(typeof(MyClass));
var sb = new StringBuilder();
serializer.Serialize(new StringWriter(sb, CultureInfo.InvariantCulture), t, namespaces);
Avatar billede arne_v Ekspert
05. februar 2011 - 02:23 #10
public string A { get; set; }
        [XmlElement(Namespace="")]
        public int B { get; set; }
        [XmlElement(Namespace="")]
        public int C { get; set; }
        [XmlElement(Namespace="")]
        public int D { get; set; }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            MyRoot mr = new MyRoot{ A="ABC", B=1, C=2, D=3 };
            XmlSerializer ser = new XmlSerializer(typeof(MyRoot));
            ser.Serialize(Console.Out, mr);
            MyRoot2 mr2 = new MyRoot2{ A="ABC", B=1, C=2, D=3 };
            XmlSerializer ser2 = new XmlSerializer(typeof(MyRoot2));
            ser2.Serialize(Console.Out, mr2);
            Console.ReadKey();
        }
    }
}

giver noget der er ekvivalent til de to former.
Avatar billede CodingJoe Nybegynder
05. februar 2011 - 12:46 #11
Hej Arne
Ja, fandt ud af at denne notationsform over mine properties under serialiseringen får den ønskede form:
[XmlElement(Namespace="")]

Jeg fik det til at virke...men vil naturligvis give points for din tid :)
Avatar billede arne_v Ekspert
05. februar 2011 - 14:54 #12
så smider jeg et svar
Avatar billede CodingJoe Nybegynder
11. februar 2011 - 16:35 #13
Hey Arne

Har du en holdning til dette? ->
http://www.eksperten.dk/spm/929425#reply_7720647
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