C# 从序列化值中的Xml节点中删除命名空间属性
我必须重新创建供应商的XML文件。我无法访问它们的代码、模式或任何内容,因此我使用C# 从序列化值中的Xml节点中删除命名空间属性,c#,xml,xmlserializer,xmldocument,xmlnode,C#,Xml,Xmlserializer,Xmldocument,Xmlnode,我必须重新创建供应商的XML文件。我无法访问它们的代码、模式或任何内容,因此我使用XmlSerializer和属性来执行此操作。我这样做是因为系统使用的是一个通用的XmlWriter,我构建它是为了编写其他系统XML文件,所以我一举两得。除了一处房产的价值外,一切都很顺利。供应商XML如下所示: <TextOutlTxt> <p style="text-align:left;margin-top:0pt;margin-bottom:0pt;"> &l
XmlSerializer
和属性来执行此操作。我这样做是因为系统使用的是一个通用的XmlWriter
,我构建它是为了编写其他系统XML文件,所以我一举两得。除了一处房产的价值外,一切都很顺利。供应商XML如下所示:
<TextOutlTxt>
<p style="text-align:left;margin-top:0pt;margin-bottom:0pt;">
<span>SUBSTA SF6 CIRCUIT BKR CONC FDN "C"</span>
</p>
</TextOutlTxt>
我肯定我忽略了什么。任何帮助都将不胜感激
更新日期2017年9月26日
所以我被要求提供更多的细节,特别是对代码目的的解释,以及一个可复制的示例。这两个都是:
[XmlRoot("OutlTxt", Namespace = "http://www.mynamespace/09262017")]
public class OutlineText
{
private string _value;
[XmlElement("TextOutlTxt")]
public XmlNode Value
{
get
{
string text = _value;
text = Regex.Replace(text, @"[\a\b\f\n\r\t\v\\""'&<>]", m => string.Join(string.Empty, m.Value.Select(c => string.Format("&#x{0:X};", Convert.ToInt32(c))).ToArray()));
string value = "\n<p style=\"text-align:left;margin-top:0pt;margin-bottom:0pt;\">\n<span>ReplaceMe</span>\n</p>\n";
XmlDocument document = new XmlDocument();
document.InnerXml = "<root>" + value + "</root>";
XmlNode innerNode = document.DocumentElement.FirstChild;
innerNode.InnerText = text;
return innerNode;
}
set
{ }
}
private OutlineText()
{ }
public OutlineText(string text)
{
_value = text;
}
}
public class XmlFileWriter
{
public void Write<T>(T sourceData, FileInfo targetFile) where T : class
{
//This is actually retrieved through a locator object, but surely no one will mind an empty
//collection for the sake of an example
Type[] knownTypes = new Type[] { };
using (FileStream targetStream = targetFile.OpenWrite())
{
//Let's see if we can get the default namespace
XmlRootAttribute xmlRootAttribute = sourceData.GetType().GetCustomAttributes<XmlRootAttribute>().FirstOrDefault();
XmlSerializer serializer = null;
if (xmlRootAttribute != null)
{
string nameSpace = xmlRootAttribute.Namespace ?? string.Empty;
XmlSerializerNamespaces nameSpaces = new XmlSerializerNamespaces();
nameSpaces.Add(string.Empty, nameSpace);
serializer = new XmlSerializer(typeof(T), new XmlAttributeOverrides(), knownTypes, xmlRootAttribute, nameSpace);
//Now we can serialize
using (StreamWriter writer = new StreamWriter(targetStream))
{
serializer.Serialize(writer, sourceData, nameSpaces);
}
}
else
{
serializer = new XmlSerializer(typeof(T), knownTypes);
//Now we can serialize
using (StreamWriter writer = new StreamWriter(targetStream))
{
serializer.Serialize(writer, sourceData);
}
}
}
}
}
public static void Main()
{
OutlineText outlineText = new OutlineText(@"SUBSTA SF6 CIRCUIT BKR CONC FDN ""C""");
XmlFileWriter fileWriter = new XmlFileWriter();
fileWriter.Write<OutlineText>(outlineText, new FileInfo(@"C:\MyDirectory\MyXml.xml"));
Console.ReadLine();
}
我已将示例代码值属性重新排列为:
private string _value;
[XmlAnyElement("TextOutlTxt", Namespace = "http://www.mynamespace/09262017")]
public XElement Value
{
get
{
string value = string.Format("<p xmlns=\"{0}\" style=\"text-align:left;margin-top:0pt;margin-bottom:0pt;\"><span>{1}</span></p>", "http://www.mynamespace/09262017", _value);
string innerXml = string.Format("<TextOutlTxt xmlns=\"{0}\">{1}</TextOutlTxt>", "http://www.mynamespace/09262017", value);
XElement element = XElement.Parse(innerXml);
//Remove redundant xmlns attributes
foreach (XElement descendant in element.DescendantsAndSelf())
{
descendant.Attributes().Where(att => att.IsNamespaceDeclaration && att.Value == "http://www.mynamespace/09262017").Remove();
}
return element;
}
set
{
_value = value == null ? null : value.ToString();
}
}
但是想要
SUBSTA SF6 CIRCUIT BKR CONC FDN "C"
将
xmlns=”“
添加到嵌入XML的原因是您的容器元素
和
被声明为在中http://www.mynamespace/09262017“
命名空间,而嵌入的文本XML元素位于空命名空间中。要解决此问题,嵌入的XML文本必须与其父元素位于同一命名空间中
下面是XML文本。请注意,XML中没有任何声明:
<p style="text-align:left;margin-top:0pt;margin-bottom:0pt;" xmlns="">SUBSTA SF6 CIRCUIT BKR CONC FDN &#x22;C&#x22;</p>
因此,相应的OutlTxt
根元素将位于http://www.mynamespace/09262017
名称空间。除非重写,否则其所有子元素也将默认为此命名空间。将嵌入的XmlNode
放置在空名称空间中视为覆盖父名称空间,因此需要xmlns=“”
属性
避免此问题的最简单方法是将嵌入的XML字符串文本自身放置在正确的命名空间中,如下所示:
<p xmlns="http://www.mynamespace/09262017" style="text-align:left;margin-top:0pt;margin-bottom:0pt;">
<span>ReplaceMe</span>
</p>
生成的XML如下所示:
SUBSTA SF6电路BKR CONC FDN“C”
请注意,我已将Value
上的属性从[xmlement]
更改为。我这样做是因为您的值
XML可能在根级别包含多个混合内容节点,例如:
开始文本中间文本结束文本
使用[xmlanyement]
可以允许返回容器节点,而不会导致额外级别的XML元素嵌套
示例工作。您将
xmlns=”“
添加到嵌入式XML的原因是您的容器元素
和
声明在中。”http://www.mynamespace/09262017“
命名空间,而嵌入的文本XML元素位于空命名空间中。要解决此问题,嵌入的XML文本必须与其父元素位于同一命名空间中
下面是XML文本。请注意,XML中没有任何声明:
<p style="text-align:left;margin-top:0pt;margin-bottom:0pt;" xmlns="">SUBSTA SF6 CIRCUIT BKR CONC FDN &#x22;C&#x22;</p>
因此,相应的OutlTxt
根元素将位于http://www.mynamespace/09262017
名称空间。除非重写,否则其所有子元素也将默认为此命名空间。将嵌入的XmlNode
放置在空名称空间中视为覆盖父名称空间,因此需要xmlns=“”
属性
避免此问题的最简单方法是将嵌入的XML字符串文本自身放置在正确的命名空间中,如下所示:
<p xmlns="http://www.mynamespace/09262017" style="text-align:left;margin-top:0pt;margin-bottom:0pt;">
<span>ReplaceMe</span>
</p>
生成的XML如下所示:
SUBSTA SF6电路BKR CONC FDN“C”
请注意,我已将Value
上的属性从[xmlement]
更改为。我这样做是因为您的值
XML可能在根级别包含多个混合内容节点,例如:
开始文本中间文本结束文本
使用[xmlanyement]
可以允许返回容器节点,而不会导致额外级别的XML元素嵌套
工作示例。您的问题现在有两个要求:
XElement
或XmlNode
上的某些Xlns=“…”
属性,以及“
=>";
)。尽管XML标准不要求这样做,但您的旧版接收系统显然需要这样做XmlNode
或XElement
对某些字符进行不必要的转义,因为转义是在输出过程中在XmlWriter
级别处理的。而微软的XmlWriter
内置实现似乎没有任何可以强制执行某些字符的功能不需要转义的Acter仍然需要转义。您需要尝试对XmlWriter
或XmlTextWriter
进行子类化(如所述,例如和),然后在写入字符串值时截取字符串值,并根据需要转义引号字符
因此,作为解决#1和#2的另一种方法,y
string text = Regex.Replace(element.Value, @"[\a\b\f\n\r\t\v\\""'&<>]", m => string.Join(string.Empty, m.Value.Select(c => string.Format("&#x{0:X};", Convert.ToInt32(c))).ToArray()));
SUBSTA SF6 CIRCUIT BKR CONC FDN &#x22;C&#x22;
SUBSTA SF6 CIRCUIT BKR CONC FDN "C"
<p style="text-align:left;margin-top:0pt;margin-bottom:0pt;" xmlns="">SUBSTA SF6 CIRCUIT BKR CONC FDN &#x22;C&#x22;</p>
[XmlRoot("OutlTxt", Namespace = "http://www.mynamespace/09262017")]
public class OutlineText
{
}
<p xmlns="http://www.mynamespace/09262017" style="text-align:left;margin-top:0pt;margin-bottom:0pt;">
<span>ReplaceMe</span>
</p>
[XmlRoot("OutlTxt", Namespace = OutlineText.Namespace)]
public class OutlineText
{
public const string Namespace = "http://www.mynamespace/09262017";
private string _value;
[XmlAnyElement("TextOutlTxt", Namespace = OutlineText.Namespace)]
public XElement Value
{
get
{
var escapedValue = EscapeTextValue(_value);
var nestedXml = string.Format("<p xmlns=\"{0}\" style=\"text-align:left;margin-top:0pt;margin-bottom:0pt;\"><span>{1}</span></p>", Namespace, escapedValue);
var outerXml = string.Format("<TextOutlTxt xmlns=\"{0}\">{1}</TextOutlTxt>", Namespace, nestedXml);
var element = XElement.Parse(outerXml);
//Remove redundant xmlns attributes
element.DescendantsAndSelf().SelectMany(e => e.Attributes()).Where(a => a.IsNamespaceDeclaration && a.Value == Namespace).Remove();
return element;
}
set
{
_value = value == null ? null : value.Value;
}
}
static string EscapeTextValue(string text)
{
return Regex.Replace(text, @"[\a\b\f\n\r\t\v\\""'&<>]", m => string.Join(string.Empty, m.Value.Select(c => string.Format("&#x{0:X};", Convert.ToInt32(c))).ToArray()));
}
private OutlineText()
{ }
public OutlineText(string text)
{
_value = text;
}
}
[XmlRoot("OutlTxt", Namespace = OutlineText.Namespace)]
public class OutlineText : IXmlSerializable
{
public const string Namespace = "http://www.mynamespace/09262017";
private string _value;
// For debugging purposes.
internal string InnerValue { get { return _value; } }
static string EscapeTextValue(string text)
{
return Regex.Replace(text, @"[\a\b\f\n\r\t\v\\""'&<>]", m => string.Join(string.Empty, m.Value.Select(c => string.Format("&#x{0:X};", Convert.ToInt32(c))).ToArray()));
}
private OutlineText()
{ }
public OutlineText(string text)
{
_value = text;
}
#region IXmlSerializable Members
XmlSchema IXmlSerializable.GetSchema()
{
return null;
}
void IXmlSerializable.ReadXml(XmlReader reader)
{
_value = ((XElement)XNode.ReadFrom(reader)).Value;
}
void IXmlSerializable.WriteXml(XmlWriter writer)
{
var escapedValue = EscapeTextValue(_value);
var nestedXml = string.Format("<p style=\"text-align:left;margin-top:0pt;margin-bottom:0pt;\"><span>{0}</span></p>", escapedValue);
writer.WriteRaw(nestedXml);
}
#endregion
}
<OutlTxt xmlns="http://www.mynamespace/09262017"><p style="text-align:left;margin-top:0pt;margin-bottom:0pt;"><span>SUBSTA SF6 CIRCUIT BKR CONC FDN "C"</span></p></OutlTxt>