diff --git a/README.md b/README.md
index 40ccca5..97ae77d 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@ A fork of the SvgNet & SvgGdi bridge (http://www.codeproject.com/KB/cs/svgnet.as
__SvgNet is now available as a Nuget:__ [SvgNet](https://www.nuget.org/packages/SvgNet/).
-__Latest version 3.4.0 is .NET Standard 2.0 and 2.1 and also .NET 8.0 (base and Windows) compatible and works with .NET Core 2.x and 3.x and .NET 5.0/6.0/7.0/8.0, but now requires .NET Framework 4.6.2 or higher__
+__Latest version 3.5.0 is .NET Standard 2.0 and 2.1 and also .NET 8.0 (base and Windows) compatible and works with .NET Core 2.x and 3.x and .NET 5.0/6.0/7.0/8.0, but now requires .NET Framework 4.6.2 or higher__
To build this version properly you need .NET 8.0.403+ SDK installed
diff --git a/SvgDocTest/DocForm.Designer.cs b/SvgDocTest/DocForm.Designer.cs
index ff9e762..fc8a398 100644
--- a/SvgDocTest/DocForm.Designer.cs
+++ b/SvgDocTest/DocForm.Designer.cs
@@ -23,135 +23,194 @@ protected override void Dispose(bool disposing) {
/// the contents of this method with the code editor.
///
private void InitializeComponent() {
- this.svgOut = new System.Windows.Forms.WebBrowser();
this.svgIn = new System.Windows.Forms.WebBrowser();
- this.button2 = new System.Windows.Forms.Button();
- this.label2 = new System.Windows.Forms.Label();
- this.label1 = new System.Windows.Forms.Label();
- this.button3 = new System.Windows.Forms.Button();
this.tbIn = new System.Windows.Forms.TextBox();
+ this.panelBottom = new System.Windows.Forms.GroupBox();
this.tbOut = new System.Windows.Forms.TextBox();
+ this.svgOut = new System.Windows.Forms.WebBrowser();
+ this.panelTop = new System.Windows.Forms.GroupBox();
+ this.panelButtons = new System.Windows.Forms.Panel();
+ this.button2 = new System.Windows.Forms.Button();
+ this.button3 = new System.Windows.Forms.Button();
this.button1 = new System.Windows.Forms.Button();
+ this.panelBottom.SuspendLayout();
+ this.panelTop.SuspendLayout();
+ this.panelButtons.SuspendLayout();
this.SuspendLayout();
//
- // svgOut
- //
- this.svgOut.Location = new System.Drawing.Point(404, 309);
- this.svgOut.MinimumSize = new System.Drawing.Size(20, 20);
- this.svgOut.Name = "svgOut";
- this.svgOut.Size = new System.Drawing.Size(495, 232);
- this.svgOut.TabIndex = 20;
- //
// svgIn
//
- this.svgIn.Location = new System.Drawing.Point(404, 41);
- this.svgIn.MinimumSize = new System.Drawing.Size(20, 20);
+ this.svgIn.AllowWebBrowserDrop = false;
+ this.svgIn.Location = new System.Drawing.Point(760, 28);
+ this.svgIn.Margin = new System.Windows.Forms.Padding(4);
+ this.svgIn.MinimumSize = new System.Drawing.Size(27, 25);
this.svgIn.Name = "svgIn";
- this.svgIn.Size = new System.Drawing.Size(495, 230);
+ this.svgIn.Size = new System.Drawing.Size(857, 420);
this.svgIn.TabIndex = 19;
//
+ // tbIn
+ //
+ this.tbIn.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+ this.tbIn.Dock = System.Windows.Forms.DockStyle.Left;
+ this.tbIn.Font = new System.Drawing.Font("Cascadia Code", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.tbIn.Location = new System.Drawing.Point(3, 28);
+ this.tbIn.Margin = new System.Windows.Forms.Padding(4);
+ this.tbIn.Multiline = true;
+ this.tbIn.Name = "tbIn";
+ this.tbIn.ScrollBars = System.Windows.Forms.ScrollBars.Both;
+ this.tbIn.Size = new System.Drawing.Size(757, 415);
+ this.tbIn.TabIndex = 14;
+ this.tbIn.Text = "";
+ //
+ // panelBottom
+ //
+ this.panelBottom.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
+ this.panelBottom.BackColor = System.Drawing.Color.LightSteelBlue;
+ this.panelBottom.Controls.Add(this.tbOut);
+ this.panelBottom.Controls.Add(this.svgOut);
+ this.panelBottom.Dock = System.Windows.Forms.DockStyle.Bottom;
+ this.panelBottom.Font = new System.Drawing.Font("Calibri", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.panelBottom.Location = new System.Drawing.Point(0, 526);
+ this.panelBottom.Name = "panelBottom";
+ this.panelBottom.Size = new System.Drawing.Size(1620, 451);
+ this.panelBottom.TabIndex = 21;
+ this.panelBottom.TabStop = false;
+ this.panelBottom.Text = "Output";
+ //
+ // tbOut
+ //
+ this.tbOut.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+ this.tbOut.Dock = System.Windows.Forms.DockStyle.Left;
+ this.tbOut.Font = new System.Drawing.Font("Cascadia Code", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.tbOut.Location = new System.Drawing.Point(3, 28);
+ this.tbOut.Margin = new System.Windows.Forms.Padding(4);
+ this.tbOut.Multiline = true;
+ this.tbOut.Name = "tbOut";
+ this.tbOut.ScrollBars = System.Windows.Forms.ScrollBars.Both;
+ this.tbOut.Size = new System.Drawing.Size(757, 420);
+ this.tbOut.TabIndex = 23;
+ this.tbOut.Text = "";
+ //
+ // svgOut
+ //
+ this.svgOut.AllowWebBrowserDrop = false;
+ this.svgOut.Location = new System.Drawing.Point(760, 28);
+ this.svgOut.Margin = new System.Windows.Forms.Padding(4);
+ this.svgOut.MinimumSize = new System.Drawing.Size(27, 25);
+ this.svgOut.Name = "svgOut";
+ this.svgOut.Size = new System.Drawing.Size(857, 420);
+ this.svgOut.TabIndex = 24;
+ //
+ // panelTop
+ //
+ this.panelTop.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
+ this.panelTop.BackColor = System.Drawing.Color.LightCoral;
+ this.panelTop.Controls.Add(this.svgIn);
+ this.panelTop.Controls.Add(this.tbIn);
+ this.panelTop.Dock = System.Windows.Forms.DockStyle.Bottom;
+ this.panelTop.Font = new System.Drawing.Font("Calibri", 12F, System.Drawing.FontStyle.Bold);
+ this.panelTop.Location = new System.Drawing.Point(0, 80);
+ this.panelTop.Name = "panelTop";
+ this.panelTop.Size = new System.Drawing.Size(1620, 446);
+ this.panelTop.TabIndex = 22;
+ this.panelTop.TabStop = false;
+ this.panelTop.Text = "Input";
+ //
+ // panelButtons
+ //
+ this.panelButtons.BackColor = System.Drawing.Color.Khaki;
+ this.panelButtons.Controls.Add(this.button2);
+ this.panelButtons.Controls.Add(this.button3);
+ this.panelButtons.Controls.Add(this.button1);
+ this.panelButtons.Dock = System.Windows.Forms.DockStyle.Top;
+ this.panelButtons.Location = new System.Drawing.Point(0, 0);
+ this.panelButtons.Name = "panelButtons";
+ this.panelButtons.Size = new System.Drawing.Size(1620, 74);
+ this.panelButtons.TabIndex = 23;
+ //
// button2
//
+ this.button2.BackColor = System.Drawing.Color.White;
+ this.button2.FlatAppearance.BorderColor = System.Drawing.Color.Navy;
+ this.button2.FlatAppearance.BorderSize = 2;
+ this.button2.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.button2.Font = new System.Drawing.Font("Cascadia Code", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.button2.ForeColor = System.Drawing.Color.DarkMagenta;
- this.button2.Location = new System.Drawing.Point(549, 3);
+ this.button2.Location = new System.Drawing.Point(603, 13);
+ this.button2.Margin = new System.Windows.Forms.Padding(4);
this.button2.Name = "button2";
- this.button2.Size = new System.Drawing.Size(242, 32);
- this.button2.TabIndex = 18;
+ this.button2.Size = new System.Drawing.Size(323, 39);
+ this.button2.TabIndex = 21;
this.button2.Text = "Run Composition Tests";
+ this.button2.UseVisualStyleBackColor = false;
this.button2.Click += new System.EventHandler(this.Button2_Click);
//
- // label2
- //
- this.label2.Font = new System.Drawing.Font("Cascadia Code", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.label2.Location = new System.Drawing.Point(12, 285);
- this.label2.Name = "label2";
- this.label2.Size = new System.Drawing.Size(136, 24);
- this.label2.TabIndex = 17;
- this.label2.Text = "Output:";
- //
- // label1
- //
- this.label1.Font = new System.Drawing.Font("Cascadia Code", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.label1.Location = new System.Drawing.Point(12, 19);
- this.label1.Name = "label1";
- this.label1.Size = new System.Drawing.Size(136, 24);
- this.label1.TabIndex = 16;
- this.label1.Text = "Input:";
- //
// button3
//
+ this.button3.BackColor = System.Drawing.Color.White;
+ this.button3.FlatAppearance.BorderColor = System.Drawing.Color.Navy;
+ this.button3.FlatAppearance.BorderSize = 2;
+ this.button3.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.button3.Font = new System.Drawing.Font("Cascadia Code", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.button3.ForeColor = System.Drawing.Color.DarkMagenta;
- this.button3.Location = new System.Drawing.Point(307, 3);
+ this.button3.Location = new System.Drawing.Point(1069, 13);
+ this.button3.Margin = new System.Windows.Forms.Padding(4);
this.button3.Name = "button3";
- this.button3.Size = new System.Drawing.Size(242, 32);
- this.button3.TabIndex = 15;
+ this.button3.Size = new System.Drawing.Size(323, 39);
+ this.button3.TabIndex = 20;
this.button3.Text = "Run Type Tests";
+ this.button3.UseVisualStyleBackColor = false;
this.button3.Click += new System.EventHandler(this.Button3_Click);
//
- // tbIn
- //
- this.tbIn.Font = new System.Drawing.Font("Cascadia Code", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.tbIn.Location = new System.Drawing.Point(12, 41);
- this.tbIn.Multiline = true;
- this.tbIn.Name = "tbIn";
- this.tbIn.Size = new System.Drawing.Size(384, 232);
- this.tbIn.TabIndex = 14;
- this.tbIn.Text = "";
- //
- // tbOut
- //
- this.tbOut.Font = new System.Drawing.Font("Cascadia Code", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.tbOut.Location = new System.Drawing.Point(12, 309);
- this.tbOut.Multiline = true;
- this.tbOut.Name = "tbOut";
- this.tbOut.Size = new System.Drawing.Size(384, 232);
- this.tbOut.TabIndex = 13;
- this.tbOut.Text = "textBox1";
- //
// button1
//
+ this.button1.BackColor = System.Drawing.Color.White;
+ this.button1.FlatAppearance.BorderColor = System.Drawing.Color.Navy;
+ this.button1.FlatAppearance.BorderSize = 2;
+ this.button1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.button1.Font = new System.Drawing.Font("Cascadia Code", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.button1.ForeColor = System.Drawing.Color.DarkMagenta;
- this.button1.Location = new System.Drawing.Point(65, 3);
+ this.button1.Location = new System.Drawing.Point(137, 13);
+ this.button1.Margin = new System.Windows.Forms.Padding(4);
this.button1.Name = "button1";
- this.button1.Size = new System.Drawing.Size(242, 32);
- this.button1.TabIndex = 12;
+ this.button1.Size = new System.Drawing.Size(323, 39);
+ this.button1.TabIndex = 19;
this.button1.Text = "Test an SVG file";
+ this.button1.UseVisualStyleBackColor = false;
this.button1.Click += new System.EventHandler(this.Button1_Click);
//
// DocForm
//
- this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(911, 555);
- this.Controls.Add(this.svgOut);
- this.Controls.Add(this.svgIn);
- this.Controls.Add(this.button2);
- this.Controls.Add(this.label2);
- this.Controls.Add(this.button3);
- this.Controls.Add(this.tbIn);
- this.Controls.Add(this.tbOut);
- this.Controls.Add(this.button1);
- this.Controls.Add(this.label1);
+ this.AutoSize = true;
+ this.ClientSize = new System.Drawing.Size(1620, 977);
+ this.Controls.Add(this.panelButtons);
+ this.Controls.Add(this.panelTop);
+ this.Controls.Add(this.panelBottom);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
+ this.Margin = new System.Windows.Forms.Padding(4);
this.Name = "DocForm";
this.Text = "DocForm";
+ this.panelBottom.ResumeLayout(false);
+ this.panelBottom.PerformLayout();
+ this.panelTop.ResumeLayout(false);
+ this.panelTop.PerformLayout();
+ this.panelButtons.ResumeLayout(false);
this.ResumeLayout(false);
- this.PerformLayout();
}
#endregion
-
- private System.Windows.Forms.WebBrowser svgOut;
private System.Windows.Forms.WebBrowser svgIn;
- private System.Windows.Forms.Button button2;
- private System.Windows.Forms.Label label2;
- private System.Windows.Forms.Label label1;
- private System.Windows.Forms.Button button3;
private System.Windows.Forms.TextBox tbIn;
+ private System.Windows.Forms.GroupBox panelBottom;
+ private System.Windows.Forms.GroupBox panelTop;
private System.Windows.Forms.TextBox tbOut;
+ private System.Windows.Forms.WebBrowser svgOut;
+ private System.Windows.Forms.Panel panelButtons;
+ private System.Windows.Forms.Button button2;
+ private System.Windows.Forms.Button button3;
private System.Windows.Forms.Button button1;
}
}
\ No newline at end of file
diff --git a/SvgDocTest/DocForm.cs b/SvgDocTest/DocForm.cs
index 1a9a48a..74edf33 100644
--- a/SvgDocTest/DocForm.cs
+++ b/SvgDocTest/DocForm.cs
@@ -18,11 +18,6 @@ public partial class DocForm : Form {
[STAThread]
private static void Main() => Application.Run(new DocForm());
- private static void RefreshBrowserFrom(WebBrowser browser, string filename) {
- browser.Navigate(new Uri(filename));
- browser.Refresh(WebBrowserRefreshOption.Completely);
- }
-
private void Button1_Click(object sender, EventArgs e) {
using (var dlg = new OpenFileDialog {
AutoUpgradeEnabled = true,
@@ -96,18 +91,18 @@ private void Button2_Click(object sender, EventArgs e) {
root.AddChild(grp2);
//output
-
+ SvgFactory.ResetNamespaces();
string s = root.WriteSVGString(true);
-
+ tbIn.Text = s;
tbOut.Text = s;
string tempFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "foo.svg");
using (var tw = new StreamWriter(tempFile, false))
tw.Write(s);
-
- svgOut.Navigate(new Uri(tempFile));
- svgOut.Refresh(WebBrowserRefreshOption.Completely);
+ panelTop.Text = $"Input: {tempFile}";
+ svgOut.RefreshFrom(tempFile);
+ svgIn.RefreshFrom(tempFile);
}
private void Button3_Click(object sender, EventArgs e) {
@@ -131,11 +126,12 @@ private void Button3_Click(object sender, EventArgs e) {
_ = MessageBox.Show("Tests completed Ok");
}
private void ProcessSvgFile(string svgFileName) {
+ panelTop.Text = $"Input: {svgFileName}";
tbIn.Text = svgFileName.LoadText();
- RefreshBrowserFrom(svgIn, svgFileName);
tbOut.Text = SvgFactory.LoadFromXML(svgFileName.LoadXml(), null).WriteSVGString(true);
File.WriteAllText(_tempFileName, tbOut.Text);
- RefreshBrowserFrom(svgOut, _tempFileName);
+ svgIn.RefreshFrom(svgFileName);
+ svgOut.RefreshFrom(_tempFileName);
}
}
}
diff --git a/SvgDocTest/Extensions.cs b/SvgDocTest/Extensions.cs
new file mode 100644
index 0000000..5e0d7d3
--- /dev/null
+++ b/SvgDocTest/Extensions.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Windows.Forms;
+
+namespace SvgDocTest {
+ public static class Extensions {
+ public static void RefreshFrom(this WebBrowser browser, string filename) {
+ browser.Navigate(new Uri(filename));
+ browser.Refresh(WebBrowserRefreshOption.Completely);
+ }
+ }
+}
diff --git a/SvgDotNetCoreTest/SvgDotNetCoreTest.csproj b/SvgDotNetCoreTest/SvgDotNetCoreTest.csproj
index 1d8245b..09773e8 100644
--- a/SvgDotNetCoreTest/SvgDotNetCoreTest.csproj
+++ b/SvgDotNetCoreTest/SvgDotNetCoreTest.csproj
@@ -2,7 +2,7 @@
Exe
12
- net8.0-windows
+ net8.0-windows;net9.0-windows
diff --git a/SvgNet/Elements/SvgElement.cs b/SvgNet/Elements/SvgElement.cs
index 7854e93..a630b4e 100644
--- a/SvgNet/Elements/SvgElement.cs
+++ b/SvgNet/Elements/SvgElement.cs
@@ -8,6 +8,8 @@
using System.Xml;
+using SvgNet.Elements;
+
namespace SvgNet.Elements;
///
/// The base class for SVG elements. It represents some part of an SVG document, either an element (rect, circle etc) or a text item. Duties include:
@@ -30,9 +32,6 @@ namespace SvgNet.Elements;
///
///
public class SvgElement {
- public const string svgNamespaceURI = "http://www.w3.org/2000/svg";
- public const string xlinkNamespaceURI = "http://www.w3.org/1999/xlink";
-
public SvgElement() => Id = GenerateNewId();
public SvgElement(string id) => Id = id;
@@ -98,15 +97,18 @@ public virtual SvgElement AddChildren(params SvgElement[] ch) {
///
///
public virtual void ReadXmlElement(XmlDocument doc, XmlElement el) {
- foreach (XmlAttribute att in el.Attributes) {
- // TODO: after namespaced attributes are supported in the writer code (WriteXmlElements) re-enable
- // their reading.
- // For now we'll skip namespaced attributes
- if (att.Name == "xmlns" || att.Name.Contains(':'))
- continue;
-
- this[att.Name] = att.Value;
- }
+ foreach (XmlAttribute att in el.Attributes)
+ if (att.Name.StartsWith("xmlns", StringComparison.Ordinal))
+#if NET5_0_OR_GREATER
+ SvgFactory._namespaces.TryAdd(att.Name, att.Value);
+#else
+ {
+ if (!SvgFactory._namespaces.ContainsKey(att.Name))
+ SvgFactory._namespaces.Add(att.Name, att.Value);
+ }
+#endif
+ else
+ this[att.Name] = att.Value;
}
///
@@ -140,8 +142,8 @@ public string WriteSVGString(bool compressAttributes, SizeF? bounds) {
//write out our SVG tree to the new XmlDocument
WriteXmlElements(doc, null);
- doc.DocumentElement.SetAttribute("xmlns", svgNamespaceURI);
- doc.DocumentElement.SetAttribute("xmlns:xlink", xlinkNamespaceURI);
+ foreach (KeyValuePair pair in SvgFactory._namespaces)
+ doc.DocumentElement.SetAttribute(pair.Key, pair.Value);
string ents = string.Empty;
if (compressAttributes)
ents = SvgFactory.CompressXML(doc, doc.DocumentElement);
@@ -167,7 +169,7 @@ public virtual void WriteXmlElements(XmlDocument doc, XmlElement parent) {
foreach (string s in _atts.Keys) _ = _atts[s] switch {
float singleValue => me.SetAttribute(s, doc.NamespaceURI, singleValue.ToString(CultureInfo.InvariantCulture)),
double doubleValue => me.SetAttribute(s, doc.NamespaceURI, doubleValue.ToString(CultureInfo.InvariantCulture)),
- _ => me.SetAttribute(s, doc.NamespaceURI, _atts[s].ToString()),
+ _ => SetAttribute(doc, me, s, _atts[s].ToString()),
};
foreach (SvgElement el in Children) el.WriteXmlElements(doc, me);
@@ -194,6 +196,16 @@ T SetNewAttributeValue(T st) {
private static string GenerateNewId() => _idcounter++.ToString();
+ protected static string SetAttribute(XmlDocument doc, XmlElement me, string name, string value) {
+ string[] parts = name.Split(':');
+ return parts.Length switch {
+ 1 => me.SetAttribute(name, doc.NamespaceURI, value),
+ 2 => me.SetAttribute(parts[1], NamespaceForPrefix("xmlns:" + parts[0]), value),
+ _ => throw new InvalidOperationException($"Attribute name has more tha one ':' => '{name}'")
+ };
+ }
+
+ private static string NamespaceForPrefix(string xmlns) => SvgFactory._namespaces.TryGetValue(xmlns, out string namespaceURI) ? namespaceURI : string.Empty;
private class DummyXmlResolver : XmlResolver {
public override System.Net.ICredentials Credentials { set { } }
diff --git a/SvgNet/Elements/SvgStyledElement.cs b/SvgNet/Elements/SvgStyledElement.cs
index d1dc62a..c3cee60 100644
--- a/SvgNet/Elements/SvgStyledElement.cs
+++ b/SvgNet/Elements/SvgStyledElement.cs
@@ -44,9 +44,21 @@ public SvgTransformList Transform {
///
///
public override void ReadXmlElement(XmlDocument doc, XmlElement el) {
- foreach (XmlAttribute att in el.Attributes) if (att.Name == "style") Style = new SvgStyle(att.Value);
- else if (att.Name == "transform") Transform = new SvgTransformList(att.Value);
- else this[att.Name] = att.Value;
+ foreach (XmlAttribute att in el.Attributes) {
+ string name = att.Name;
+ string value = att.Value;
+ switch (name) {
+ case "style":
+ Style = new SvgStyle(value);
+ break;
+ case "transform":
+ Transform = new SvgTransformList(value);
+ break;
+ default:
+ this[name] = value;
+ break;
+ }
+ }
}
///
@@ -58,20 +70,25 @@ public override void ReadXmlElement(XmlDocument doc, XmlElement el) {
///
public override void WriteXmlElements(XmlDocument doc, XmlElement parent) {
XmlElement me = doc.CreateElement("", Name, doc.NamespaceURI);
- foreach (string s in _atts.Keys) {
- object attribute = _atts[s];
- if (attribute != null) if (s == "style") WriteStyle(doc, me, attribute);
- else if (s == "transform") WriteTransform(doc, me, attribute);
- else {
- // xlink qualified attributes are an special case because they need an special namespace
- (bool isPrefixed, string localName) = s.IsPrefixedBy("xlink:");
- _ = isPrefixed
- ? me.SetAttribute(localName, xlinkNamespaceURI, _atts[s].ToString())
- : me.SetAttribute(s, doc.NamespaceURI, _atts[s].ToString());
- }
+ foreach (string name in _atts.Keys) {
+ object attribute = _atts[name];
+ if (attribute is null)
+ continue;
+ switch (name) {
+ case "style":
+ WriteStyle(doc, me, attribute);
+ break;
+ case "transform":
+ WriteTransform(doc, me, attribute);
+ break;
+ default:
+ SetAttribute(doc, me, name, attribute.ToString());
+ break;
+ }
}
- foreach (SvgElement el in Children) el.WriteXmlElements(doc, me);
+ foreach (SvgElement el in Children)
+ el.WriteXmlElements(doc, me);
_ = parent == null ? doc.AppendChild(me) : parent.AppendChild(me);
}
diff --git a/SvgNet/Extensions/StringExtensions.cs b/SvgNet/Extensions/StringExtensions.cs
index 0f640ea..0e460c5 100644
--- a/SvgNet/Extensions/StringExtensions.cs
+++ b/SvgNet/Extensions/StringExtensions.cs
@@ -16,17 +16,6 @@ public static int ParseHex(this string s, int startIndex, int length = 1)
=> int.Parse(s.Substring(startIndex, length), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
#endif
- public static IPB IsPrefixedBy(this string s, string prefix)
- => !s.StartsWith(prefix, StringComparison.InvariantCulture)
- ? new IPB(false, null)
- : new IPB(true,
-#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
- s[prefix.Length..]
-#else
- s.Substring(prefix.Length)
-#endif
- );
-
public static string SkipFirst(this string s)
#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
=> s[1..];
@@ -34,9 +23,17 @@ public static string SkipFirst(this string s)
=> s.Substring(1);
#endif
+#if NET8_0_OR_GREATER
+ private static readonly Buffers.SearchValues digits = Buffers.SearchValues.Create(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']);
+#else
private static readonly char[] digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
+#endif
public static bool TrySplitNumberAndSuffix(this string s, out string number, out string suffix) {
+#if NET8_0_OR_GREATER
+ int i = s.AsSpan().LastIndexOfAny(digits) + 1;
+#else
int i = s.LastIndexOfAny(digits) + 1;
+#endif
suffix = number = null;
if (i == 0)
return false;
@@ -68,14 +65,3 @@ public static bool TryParseTransformation(this string s, out string name, out fl
return true;
}
}
-
-public readonly struct IPB(bool isPrefixed, string tail) {
- public readonly bool IsPrefixed = isPrefixed;
- public readonly string Tail = tail;
-
- public void Deconstruct(out bool isPrefixed, out string tail) {
- isPrefixed = IsPrefixed;
- tail = Tail;
- }
-}
-
diff --git a/SvgNet/SvgFactory.cs b/SvgNet/SvgFactory.cs
index e939c08..816a933 100644
--- a/SvgNet/SvgFactory.cs
+++ b/SvgNet/SvgFactory.cs
@@ -16,6 +16,9 @@ namespace SvgNet;
/// Static methods to produce/write/copy Svg documents reside in this class.
///
public static class SvgFactory {
+ public const string svgNamespaceURI = "http://www.w3.org/2000/svg";
+ public const string xlinkNamespaceURI = "http://www.w3.org/1999/xlink";
+
///
/// Used by LoadFromXML
///
@@ -56,6 +59,8 @@ public static SvgElement CloneElement(SvgElement el) {
return clone;
}
+ internal static Dictionary _namespaces = new() { ["xmlns"] = svgNamespaceURI, ["xmlns:xlink"] = xlinkNamespaceURI };
+
///
/// Given an xml document and (optionally) a particular element to start from, read the xml nodes and construct
/// a tree of objects. Xml tags that do not correspond to a particular class will be
@@ -68,6 +73,7 @@ public static SvgElement CloneElement(SvgElement el) {
///
///
public static SvgElement LoadFromXML(XmlDocument doc, XmlElement el) {
+ ResetNamespaces();
if (el == null) {
foreach (XmlNode noddo in doc.ChildNodes) {
if (noddo.GetType() == typeof(XmlElement)) {
@@ -220,6 +226,9 @@ private static void RecLoadFromXML(SvgElement e, XmlDocument doc, XmlElement el)
}
}
+ public static void ResetNamespaces() => _namespaces = new() { ["xmlns"] = svgNamespaceURI, ["xmlns:xlink"] = xlinkNamespaceURI };
+
+
private struct EntitySingleton {
public string AttributeName;
public XmlElement Element;
diff --git a/SvgNet/SvgNet.csproj b/SvgNet/SvgNet.csproj
index dbe2e0e..811a10d 100644
--- a/SvgNet/SvgNet.csproj
+++ b/SvgNet/SvgNet.csproj
@@ -1,13 +1,13 @@
- netstandard2.0;netstandard2.1;net8.0
- $(TargetFrameworks);net462;net8.0-windows
- true
+ netstandard2.0;netstandard2.1;net8.0;net9.0
+ $(TargetFrameworks);net462;net8.0-windows;net9.0-windows
+ true
preview
SVG
SvgNet
- 3.4.0
+ 3.5.0
SvgNet
svgnetdoc.xml
CS1591
diff --git a/SvgNetUnitTests/SvgNetUnitTests.csproj b/SvgNetUnitTests/SvgNetUnitTests.csproj
index 285405c..305dd26 100644
--- a/SvgNetUnitTests/SvgNetUnitTests.csproj
+++ b/SvgNetUnitTests/SvgNetUnitTests.csproj
@@ -1,7 +1,7 @@
preview
- net8.0
+ net8.0;net9.0
SvgNet