Skip to content

Commit

Permalink
Add an option for WriteNode to keep attribute namespaces
Browse files Browse the repository at this point in the history
* Adds an optional parameter to WriteNode to specify what attribute
  namespaces should be retained
* Supports a FlexBridge fix https://jira.sil.org/browse/LT-21388
  where xml:space was being saved as 'space' which on a further
  write by a normal xml serializer would then drop spaces

+semver:minor
  • Loading branch information
jasonleenaylor committed Oct 30, 2024
1 parent e63461f commit b5efcc9
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 8 deletions.
36 changes: 34 additions & 2 deletions SIL.Core.Tests/Xml/XmlUtilsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,36 @@ public void WriteNode_DoesNotIndentChildWhenSuppressed()
}
Assert.That(output.ToString(), Is.EqualTo(expectedOutput));
}

[Test]
public void WriteNode_PreserveNamespacesArePreserved()
{
string input = @"<text><span class='bold' xml:space='preserve'> </span></text>";
string expectedOutput =
"<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n"
+ "<root>\r\n"
+ " <text>\r\n"
+ " <span\r\n"
+ " class=\"bold\"\r\n"
+ " xml:space=\"preserve\"> </span>\r\n"
+ " </text>\r\n"
+ "</root>";
var output = new StringBuilder();
var preserveNamespace = new HashSet<string>
{
"xml"
};
using (var writer = XmlWriter.Create(output, CanonicalXmlSettings.CreateXmlWriterSettings()))
{
writer.WriteStartDocument();
writer.WriteStartElement("root");
XmlUtils.WriteNode(writer, input, new HashSet<string>(), preserveNamespace);
writer.WriteEndElement();
writer.WriteEndDocument();
}
Assert.That(output.ToString(), Is.EqualTo(expectedOutput));
}

/// <summary>
/// This verifies that suppressing pretty-printing of children works for spans nested in spans nested in text.
/// </summary>
Expand All @@ -191,8 +221,10 @@ public void WriteNode_DoesNotIndentChildWhenTwoLevelsSuppressed()
+ " class=\"italic\">bit</span>bt</span></text>\r\n"
+ "</root>";
var output = new StringBuilder();
var suppressIndentingChildren = new HashSet<string>();
suppressIndentingChildren.Add("text");
var suppressIndentingChildren = new HashSet<string>
{
"text"
};
using (var writer = XmlWriter.Create(output, CanonicalXmlSettings.CreateXmlWriterSettings()))
{
writer.WriteStartDocument();
Expand Down
21 changes: 15 additions & 6 deletions SIL.Core/Xml/XmlUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -970,10 +970,11 @@ public static string GetTitleOfHtml(XmlDocument dom, string defaultIfMissing)
/// <param name="writer"></param>
/// <param name="dataToWrite"></param>
/// <param name="suppressIndentingChildren"></param>
public static void WriteNode(XmlWriter writer, string dataToWrite, HashSet<string> suppressIndentingChildren)
/// <param name="preserveNamespaces">a set of namespaces to preserve when writing out elements</param>
public static void WriteNode(XmlWriter writer, string dataToWrite, HashSet<string> suppressIndentingChildren, HashSet<string> preserveNamespaces = null)
{
XElement element = XDocument.Parse(dataToWrite).Root;
WriteNode(writer, element, suppressIndentingChildren);
WriteNode(writer, element, suppressIndentingChildren, preserveNamespaces);
}

/// <summary>
Expand All @@ -984,11 +985,12 @@ public static void WriteNode(XmlWriter writer, string dataToWrite, HashSet<strin
/// <param name="writer"></param>
/// <param name="dataToWrite"></param>
/// <param name="suppressIndentingChildren"></param>
public static void WriteNode(XmlWriter writer, XElement dataToWrite, HashSet<string> suppressIndentingChildren)
/// <param name="preserveNamespaces">a set of namespaces to preserve when writing out elements</param>
public static void WriteNode(XmlWriter writer, XElement dataToWrite, HashSet<string> suppressIndentingChildren, HashSet<string> preserveNamespaces = null)
{
if (dataToWrite == null)
return;
WriteElementTo(writer, dataToWrite, suppressIndentingChildren);
WriteElementTo(writer, dataToWrite, suppressIndentingChildren, preserveNamespaces);
}

/// <summary>
Expand All @@ -997,11 +999,18 @@ public static void WriteNode(XmlWriter writer, XElement dataToWrite, HashSet<str
/// <param name="writer"></param>
/// <param name="element"></param>
/// <param name="suppressIndentingChildren"></param>
private static void WriteElementTo(XmlWriter writer, XElement element, HashSet<string> suppressIndentingChildren)
/// <param name="preserveNamespaces">a set of namespaces to preserve when writing out elements</param>
private static void WriteElementTo(XmlWriter writer, XElement element, HashSet<string> suppressIndentingChildren, HashSet<string> preserveNamespaces = null)
{
writer.WriteStartElement(element.Name.LocalName);
foreach (var attr in element.Attributes())
writer.WriteAttributeString(attr.Name.LocalName, attr.Value);
{
var ns = attr.Name.NamespaceName;
if(preserveNamespaces != null && preserveNamespaces.Contains(ns))
writer.WriteAttributeString(attr.Name.LocalName, attr.Name.NamespaceName, attr.Value);
else
writer.WriteAttributeString(attr.Name.LocalName, attr.Value);
}
// The writer automatically suppresses indenting children for any element that it detects has text children.
// However, it won't do this for the first child if that is an element, even if it later encounters text children.
// Also, there may be a parent where text including white space is significant, yet it is possible for the
Expand Down

0 comments on commit b5efcc9

Please sign in to comment.