简体   繁体   中英

How to deserialize a XML file to a C# object (.svg) successfully?

I want to add text to a icon and use that icon on a website where the icon is shown with added text inside. As an example: think of a cloud-icon with a number in it where the number is the precipitation probability. The value of that number changes so it must be possible to change the text dynamically.

I use Inkscape.org as a drawing program that creates a .svg file. It is kind of XML, I guess. I thought I just use a online converter from .xml -> C# object classes ( https://xmltocsharp.azurewebsites.net ) and deserialize it then change one value and serialize it again if possible in to memory and then use that as an image on a webpage. But I get an error at the deserialization step

http://www.w3.org/2000/svg'> was not expected.

I did try different class models - but nothing worked. I am unsure if I am pursuing the right solution.

I want to be able to have a scalable icon with text in it and I must be able to change the text in the icon and show it to website users.

What shall I do?

I just want to be able to edit the last line of the .svg dynamically. Or do I have to go a different route like icon.svg as background and number.svg on top (two files instead of one)?

Thank you for your help, it is much appreciated

Here is the .svg file of the cloud icon with added text "Test", I would like to be able to change "Test" in a different string in C#:

<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <path clip-rule="evenodd" d="m20.8403 4.4685c-.5663-2.3963-2.6273-4.1744-5.0903-4.1744-2.8995 0-5.25 2.4616-5.25 5.5001 0 .1964.0113.3896.03.5799-.8955.3771-1.53 1.2924-1.53 2.3664 0 1.4097 1.0913 2.5535 2.4375 2.5535h9.3c1.8023 0 3.2625-1.5305 3.2625-3.4179 0-1.8509-1.4063-3.3493-3.1597-3.4076" fill="#e5e5e5" fill-rule="evenodd"/>
  <circle clip-rule="evenodd" cx="15.533335" cy="9.787135" fill="#ffd02f" fill-rule="evenodd" r="6"/>
  <path d="m3.6992 20.6764c-1.7637 0-3.1992-1.4297-3.1992-3.187 0-1.3047.7881-2.4639 2.0088-2.9531l.3496-.1401-.0391-.375c-.0264-.2578-.043-.52-.043-.7856 0-4.103 3.3496-7.4414 7.4678-7.4414 3.4375 0 6.4141 2.3223 7.2402 5.6479l.0918.3672.3779.0117c2.417.0767 4.3105 2.0186 4.3105 4.4209 0 2.4453-1.9971 4.4346-4.4512 4.4346h-14.1141z" fill="#fff"/>
  <path d="m10.2441 6.2941c3.2066 0 5.9842 2.1664 6.7547 5.2684l.1824.7346.7565.0239c2.1459.0677 3.827 1.7899 3.827 3.9207 0 2.1697-1.7726 3.9348-3.9514 3.9348h-14.114c-1.4884-.0001-2.6993-1.2054-2.6993-2.6871 0-1.0995.6649-2.0764 1.694-2.4888l.7005-.2806-.0778-.7506c-.027-.261-.0402-.5011-.0402-.7341 0-3.8274 3.1256-6.9412 6.9676-6.9412m0-1c-4.4004 0-7.9677 3.5543-7.9677 7.9412 0 .2836.0171.5627.0455.8372-1.3589.5446-2.3219 1.8662-2.3219 3.4169 0 2.0353 1.6561 3.687 3.6993 3.687h14.1141c2.7352 0 4.9514-2.2099 4.9514-4.9348 0-2.6729-2.1342-4.8361-4.7954-4.9202-.8595-3.46-3.9873-6.0273-7.7253-6.0273z" fill="#1d1d33"/>
  <path clip-rule="evenodd" d="m18.606967 8.7411167c-.5663-2.3963-2.6273-4.1744-5.0903-4.1744-2.8995 0-5.25 2.4616-5.25 5.5001003 0 .1964.0113.3896.03.5799-.8955.3771-1.53 1.2924-1.53 2.3664 0 1.4097 1.0913 2.5535 2.4374997 2.5535h9.3000003c1.8023 0 3.2625-1.5305 3.2625-3.4179 0-1.8509-1.4063-3.3493003-3.1597-3.4076003" fill="#e5e5e5" fill-rule="evenodd"/>
  <text style="font-weight:bold;font-size:6.62016;font-family:monospace;letter-spacing:0;word-spacing:0;stroke-width:.354651" x="3.696808" y="17.625877">
    <tspan stroke-width=".354651" x="3.696808" y="17.625877">TEST</tspan>
  </text>
</svg>

You don't really need deserialized C# class instances here. Your search led you to something that may sound similar to a beginner (serialize and deserialize objects to/from XML), but it's completely unnecessary here.

Instead, as a rough outline of what you could do, load the SVG as an XML document :

var svg = XDocument.Parse(xmlString);

Then select the element you want to change:

var tspan = (XText) svg.XPathSelectElement("//*[localName()='tspan']");
// Note: Above way of selecting the tspan is easier to start with
// because you don't have to care about namespaces

And change away:

tspan.Value = "New text";

And save it again in the end:

svg.Save(fileName);

May need some tweaking (can't test the code right now), but that's the rough idea.

You shouldn't bother with XML (de)serialization or the SVG object model in a simple case like this.

Instead, just make the default text in Inkscape something like PLACEHOLDER (or anything else you know won't appear otherwise in the SVG XML), and use simple string replacement, ie

var svgXml = ReadThatXMLAsAString();
svgXml = svgXml.replace("PLACEHOLDER", "42");
EmitThatXMLToTheUserSomehow(svgXml);

@AKX thanks so much!

Here the final code:

        StreamReader reader = new StreamReader(@"SvgTest.svg");

        var input = reader.ReadToEnd();
        
        //find the text that should be replaced
        input = input.Replace("TEST", "YES");
        reader.Close();
        
        //test -> yes the replace worked TEST->YES
        RtxbxShow.Text = input;

        //now show that svg icon in a picturebox (nuget https://github.com/vvvv/SVG)
        var mySvg = SvgDocument.FromSvg<SvgDocument>(input);
        PicbxShow2.Image = mySvg.Draw(240,240);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM