[英]XSD to XML. Multiple namepaces without prefixes. How to?
我正在使用XSD文件通過xsd.exe生成C#代碼並使用生成的代碼序列化XML。
問題是我必須生成一個具有defaut / root xmlns命名空間的XML文件,以及一個在該元素上定義另一個“原始”命名空間的元素(沒有前綴)。
這是一個輕量級示例(不是整個XML),用於說明目的:
<?xml version="1.0" encoding="utf-16"?>
<Request xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://mynamespace">
<ABC>STACKOVERFLOW</ABC>
<Method Name="TEST" xmlns="http://myothernamespace">
<DEF>123456</DEF>
</Method>
</Request>
我找不到在Method元素(沒有前綴)上“插入”第二個xmlns屬性的方法。
事實是我不能使用前綴,因為這個XML被發送到另一端沒有使用XML反序列化器的應用程序,但是它將XML解析為字符串並尋找精確的字符串匹配(當然這不是可以改變這個“接收”應用程序)。
我在XSD中嘗試了很多不同的東西,但沒有任何作用:(我正在使用MSMQ傳輸XML消息,所以我不是自己序列化請求(只是給請求對象提供正確的參數,並在場景后面處理序列化) )。
我可以使用XmlSerializer將XML序列化為沒有第二個xmlns的字符串,並在發送之前通過編碼將其添加到XML(到字符串),但這很臟並且讓我這樣做只是為了添加這個“方法元素的xmlns“屬性。
有沒有辦法通過純XSD(通過使用xsd.exe生成.NET代碼)來解決這個問題?
希望我的問題很清楚,希望有些人能夠回答
提前致謝 !
像這樣定義你的類型:
[XmlRoot("Method")]
public class MyMethod
{
[XmlAttribute]
public String Name { get; set; }
[XmlElement]
public int DEF { get; set; }
}
[XmlRoot("Request", Namespace="http://mynamespace")]
public class MyRequest
{
[XmlElement]
public String ABC { get; set; }
[XmlElement(Namespace="http://myothernamespace")]
public MyMethod Method { get; set; }
}
支持代碼:
static TextWriter GetWriter(bool wantSave)
{
if (wantSave)
{
var fs = new FileStream(StorageFile, FileMode.Create);
return new StreamWriter(fs, new UTF8Encoding());
}
return Console.Out;
}
private static void ShoworSave(MyRequest r, bool wantSave)
{
if (r==null)
{
Console.WriteLine(" --null--");
return;
}
Console.WriteLine("\n");
var writerSettings = new XmlWriterSettings
{
OmitXmlDeclaration = true,
Indent = true
};
using (XmlWriter xmlWriter =
XmlWriter.Create(GetWriter(wantSave), writerSettings))
{
XmlSerializer ser = new XmlSerializer(r.GetType());
var ns = new XmlSerializerNamespaces();
ns.Add("", "http://mynamespace"); // default xmlns
ser.Serialize(xmlWriter, r, ns);
}
Console.WriteLine("\n");
}
然后像這樣使用:
var request = new MyRequest
{
ABC = "HelloWorld",
Method = new MyMethod
{
Name="TEST",
DEF=123456
}
};
SaveOrShow(request, false);
結果:
<Request xmlns="http://mynamespace">
<ABC>HelloWorld</ABC>
<Method Name="TEST" xmlns="http://myothernamespace">
<DEF>123456</DEF>
</Method>
</Request>
Xml序列化程序允許您指定命名空間映射,從而可以為序列化輸出提供命名空間前綴列表以及它們映射到的實際命名空間。 要設置默認的xml命名空間及其前綴,請使用前綴“”(空字符串)。
所以我使用的代碼指定了默認命名空間。
我還使用適當的xml序列化程序屬性修飾了各種類型和成員,以獲得正確的命名空間。
乍一看,您可能認為在代碼中的幾個不同位置使用xml命名空間字符串(在您的“http:// mynamespace”示例中)違反了“不要重復自己”的清晰編碼格言。 但事實並非如此。 在我使用它的一個地方,它設置了該類型的XML命名空間。 在另一個地方,它指定序列化程序的默認xml命名空間。
如果我沒有指定后者那么你會得到一個前綴; 這會給你一個語義上等效的xml信息集,但是因為你說你的接收器應用程序不是真正的xml感知,它會打破那個接收器。
另外,關於你關於xsd.exe和代碼生成的問題,不確定你得到了什么,但考慮到這一點:Xsd.exe只是一個工具。 獲取該工具的輸出並進行調整,編輯它沒有任何問題。 如果您的類型相對簡單,您可能會發現在C#中定義類型更容易,如上所示。 如果您將XSD作為源代碼,那么您將需要依賴xsd.exe工具。 在這種情況下,您需要在xsd文檔中的適當位置指定這些名稱空間。 您選擇哪個選項取決於您。
如果你把xmlns="http://myothernamespace">
放在你的根節點上,那么所有未加前綴的節點將被視為在該命名空間中。 以上格式稱為默認命名空間。 您必須添加更多代碼才能在Xpath中使用它。
例如
在您的示例SomeNode.SelectSingleNode("Test")
將無法正常工作。
您需要手動將命名空間添加到NameSpaceManager的實例,並使用帶有管理器的重載。
例如
<Test>
和
<Test xmlns="http://myothernamespace">
是不同的動物。
在正確序列化您的實例時,XmlSerialiserNamespaces將其添加前綴為“”,然后將其傳遞給序列化程序。
以前的問題,這是在VB.Net,但你會明白的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.