এক্সএমএলসিরাইজার: অপ্রয়োজনীয় এক্সসি এবং এক্সএসডি নেমস্পেসগুলি সরান


132

এক্সএমএসআরশায়ালাইজারকে কনফিগার করার কোনও উপায় আছে যাতে এটি মূল উপাদানটিতে ডিফল্ট নেমস্পেস লিখতে না পারে?

আমি যা পাই তা হ'ল:

<?xml ...>
<rootelement xmlns:xsi="..." xmlns:xsd="...">
</rootelement>

এবং আমি উভয় এক্সএমএলএন ঘোষণার অপসারণ করতে চাই।

এর সদৃশ : xMLns = "…" না পেয়ে কীভাবে কোনও বস্তুটি এক্সএমএলকে সিরিয়ালাইজ করা যায়?

উত্তর:


63

যেহেতু ডেভ আমাকে .NET- এ কোনও বস্তু সিরিয়াল করার সময় সমস্ত এক্সসি এবং এক্সএসডি নেমস্পেস ছেড়ে দেওয়ার বিষয়ে আমার উত্তরটি পুনরাবৃত্তি করতে বলেছিল , তাই আমি এই পোস্টটি আপডেট করেছি এবং আমার উত্তরটি পূর্ব-বর্ণিত লিঙ্ক থেকে পুনরাবৃত্তি করেছি। এই উত্তরে ব্যবহৃত উদাহরণটি অন্য প্রশ্নের জন্য ব্যবহৃত একই উদাহরণ। যা অনুসরণ করা হয় তা অনুলিপি করা হয়, ভারব্যাটিম।


মাইক্রোসফ্টের ডকুমেন্টেশন এবং বেশ কয়েকটি সমাধান অনলাইনে পড়ার পরে, আমি এই সমস্যার সমাধান খুঁজে পেয়েছি। এটি বিল্ট-ইন XmlSerializerএবং কাস্টম এক্সএমএল সিরিয়ালাইজেশন উভয়ের সাথেই কাজ করে IXmlSerialiazble

ঝকঝকে করতে, আমি MyTypeWithNamespacesএখন পর্যন্ত এই প্রশ্নের উত্তরে ব্যবহৃত একই এক্সএমএল নমুনাটি ব্যবহার করব ।

[XmlRoot("MyTypeWithNamespaces", Namespace="urn:Abracadabra", IsNullable=false)]
public class MyTypeWithNamespaces
{
    // As noted below, per Microsoft's documentation, if the class exposes a public
    // member of type XmlSerializerNamespaces decorated with the 
    // XmlNamespacesDeclarationAttribute, then the XmlSerializer will utilize those
    // namespaces during serialization.
    public MyTypeWithNamespaces( )
    {
        this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
            // Don't do this!! Microsoft's documentation explicitly says it's not supported.
            // It doesn't throw any exceptions, but in my testing, it didn't always work.

            // new XmlQualifiedName(string.Empty, string.Empty),  // And don't do this:
            // new XmlQualifiedName("", "")

            // DO THIS:
            new XmlQualifiedName(string.Empty, "urn:Abracadabra") // Default Namespace
            // Add any other namespaces, with prefixes, here.
        });
    }

    // If you have other constructors, make sure to call the default constructor.
    public MyTypeWithNamespaces(string label, int epoch) : this( )
    {
        this._label = label;
        this._epoch = epoch;
    }

    // An element with a declared namespace different than the namespace
    // of the enclosing type.
    [XmlElement(Namespace="urn:Whoohoo")]
    public string Label
    {
        get { return this._label; }
        set { this._label = value; }
    }
    private string _label;

    // An element whose tag will be the same name as the property name.
    // Also, this element will inherit the namespace of the enclosing type.
    public int Epoch
    {
        get { return this._epoch; }
        set { this._epoch = value; }
    }
    private int _epoch;

    // Per Microsoft's documentation, you can add some public member that
    // returns a XmlSerializerNamespaces object. They use a public field,
    // but that's sloppy. So I'll use a private backed-field with a public
    // getter property. Also, per the documentation, for this to work with
    // the XmlSerializer, decorate it with the XmlNamespaceDeclarations
    // attribute.
    [XmlNamespaceDeclarations]
    public XmlSerializerNamespaces Namespaces
    {
        get { return this._namespaces; }
    }
    private XmlSerializerNamespaces _namespaces;
}

এই ক্লাসে এটাই। এখন, কেউ কেউ XmlSerializerNamespacesতাদের ক্লাসের মধ্যে কোথাও একটি বিষয় থাকার বিষয়ে আপত্তি জানায় ; তবে আপনি দেখতে পাচ্ছেন, আমি এটি খুব সুন্দরভাবে ডিফল্ট কনস্ট্রাক্টারে টুকরো টুকরো করে ফেলেছি এবং নেমস্পেসগুলি ফিরিয়ে দেওয়ার জন্য একটি সরকারী সম্পত্তি উন্মুক্ত করেছি।

এখন, ক্লাসটি সিরিয়াল করার সময় এলে আপনি নিম্নলিখিত কোডটি ব্যবহার করবেন:

MyTypeWithNamespaces myType = new MyTypeWithNamespaces("myLabel", 42);

/******
   OK, I just figured I could do this to make the code shorter, so I commented out the
   below and replaced it with what follows:

// You have to use this constructor in order for the root element to have the right namespaces.
// If you need to do custom serialization of inner objects, you can use a shortened constructor.
XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces), new XmlAttributeOverrides(),
    new Type[]{}, new XmlRootAttribute("MyTypeWithNamespaces"), "urn:Abracadabra");

******/
XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces),
    new XmlRootAttribute("MyTypeWithNamespaces") { Namespace="urn:Abracadabra" });

// I'll use a MemoryStream as my backing store.
MemoryStream ms = new MemoryStream();

// This is extra! If you want to change the settings for the XmlSerializer, you have to create
// a separate XmlWriterSettings object and use the XmlTextWriter.Create(...) factory method.
// So, in this case, I want to omit the XML declaration.
XmlWriterSettings xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = true;
xws.Encoding = Encoding.UTF8; // This is probably the default
// You could use the XmlWriterSetting to set indenting and new line options, but the
// XmlTextWriter class has a much easier method to accomplish that.

// The factory method returns a XmlWriter, not a XmlTextWriter, so cast it.
XmlTextWriter xtw = (XmlTextWriter)XmlTextWriter.Create(ms, xws);
// Then we can set our indenting options (this is, of course, optional).
xtw.Formatting = Formatting.Indented;

// Now serialize our object.
xs.Serialize(xtw, myType, myType.Namespaces);

একবার আপনি এটি করে নিলে আপনার নিম্নলিখিত আউটপুটটি পাওয়া উচিত:

<MyTypeWithNamespaces>
    <Label xmlns="urn:Whoohoo">myLabel</Label>
    <Epoch>42</Epoch>
</MyTypeWithNamespaces>

ওয়েব সার্ভিস কলের জন্য এক্সএমএলকে ক্রমিকিত করা ক্লাসগুলির গভীর শ্রেণিবদ্ধ সহ আমি একটি সাম্প্রতিক প্রকল্পে এই পদ্ধতিটি সফলভাবে ব্যবহার করেছি। মাইক্রোসফ্টের ডকুমেন্টেশনগুলি XmlSerializerNamespacesএকবার তৈরি করার পরে সর্বজনীনভাবে অ্যাক্সেসযোগ্য সদস্যের সাথে কী করবেন সে সম্পর্কে খুব স্পষ্ট নয় এবং অনেকেই মনে করেন এটি অকেজো। তবে তাদের ডকুমেন্টেশনগুলি অনুসরণ করে এবং এটি উপরে বর্ণিত পদ্ধতিতে ব্যবহার করে আপনি কীভাবে এক্সএমএলসিরাইজার আপনার ক্লাসের জন্য এক্সএমএল উত্সাহিত আচরণের অবলম্বন না করে বা বাস্তবায়নের মাধ্যমে "আপনার নিজের নিজস্ব" রোলিং "অবিরত না করে তা কাস্টমাইজ করতে পারেন IXmlSerializable

এটি আমার প্রত্যাশা যে এই উত্তরটি একবারে এবং সর্বোপরি, কীভাবে by দ্বারা উত্পাদিত মান xsiএবং xsdনাম স্থান থেকে মুক্তি পাবেন XmlSerializer

আপডেট: আমি কেবলমাত্র নিশ্চিত করতে চাই যে আমি সমস্ত নেমস্পেসগুলি সরিয়ে দেওয়ার বিষয়ে ওপি-র প্রশ্নের উত্তর দিয়েছি। উপরের আমার কোডগুলি এটির জন্য কাজ করবে; কিভাবে, তা আমাকে দেখাতে দাও. এখন, উপরের উদাহরণে, আপনি সত্যিই সমস্ত নেমস্পেসগুলি থেকে মুক্তি পেতে পারবেন না (কারণ এখানে দুটি নেমস্পেস ব্যবহার রয়েছে)। আপনার এক্সএমএল ডকুমেন্টের কোথাও আপনার এমন কিছু হওয়া দরকার xmlns="urn:Abracadabra" xmlns:w="urn:Whoohoo। উদাহরণের শ্রেণিটি যদি বৃহত্তর নথির অংশ হয় তবে কোথাও কোথাও একটি নেমস্পেসের (অথবা উভয়) Abracadbraএবং একটির জন্য ঘোষণা করতে হবে Whoohoo। যদি তা না হয় তবে একটি বা উভয় নেমস্পেসের উপাদানটি অবশ্যই কোনও ধরণের উপসর্গ দিয়ে সজ্জিত করতে হবে (আপনার দুটি ডিফল্ট নেমস্পেস থাকতে পারে না, তাই না?) সুতরাং, এই উদাহরণস্বরূপ, Abracadabraডিফল্ট নাম স্থান। আমি আমার MyTypeWithNamespacesক্লাসের ভিতরে Whoohooনেমস্পেসের মতো একটি নেমস্পেস উপসর্গ যুক্ত করতে পারতাম :

public MyTypeWithNamespaces
{
    this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
        new XmlQualifiedName(string.Empty, "urn:Abracadabra"), // Default Namespace
        new XmlQualifiedName("w", "urn:Whoohoo")
    });
}

এখন, আমার শ্রেণির সংজ্ঞায় আমি ইঙ্গিত দিয়েছি যে <Label/>উপাদানটি নামস্থানে রয়েছে "urn:Whoohoo", সুতরাং আমাকে আর কিছু করার দরকার নেই। যখন আমি এখন আমার উপরের সিরিয়ালাইজেশন কোডটি অপরিবর্তিত রেখে সিরিয়ালাইজ করছি, এটি আউটপুট:

<MyTypeWithNamespaces xmlns:w="urn:Whoohoo">
    <w:Label>myLabel</w:Label>
    <Epoch>42</Epoch>
</MyTypeWithNamespaces>

যেহেতু <Label>বাকী নথির থেকে আলাদা নেমস্পেসে রয়েছে, এটি অবশ্যই কোনও কোনওভাবে একটি নেমস্পেস দিয়ে "সজ্জিত" হতে হবে। লক্ষ্য করুন যে এখনও কোনও নাম xsiএবং xsdস্থান নেই।


এটি অন্য প্রশ্নের আমার উত্তর শেষ করে। তবে আমি নিশ্চিত করতে চেয়েছিলাম যে কোনও নামস্থান ব্যবহার না করার বিষয়ে আমি ওপি-র প্রশ্নের জবাব দিয়েছি, কারণ আমার মনে হয় আমি এখনও এটিকে সত্যই সম্বোধন করিনি। অনুমান <Label>নথির বিশ্রাম, এই ক্ষেত্রে হিসাবে একই নামস্থান অংশ urn:Abracadabra:

<MyTypeWithNamespaces>
    <Label>myLabel<Label>
    <Epoch>42</Epoch>
</MyTypeWithNamespaces>

আপনার নির্মাতা আমার প্রথম কোড উদাহরণে যেমন দেখতে পাবেন তেমনই ডিফল্ট নাম স্থানটি পুনরুদ্ধার করার জন্য সর্বজনীন সম্পত্তি সহ:

// As noted below, per Microsoft's documentation, if the class exposes a public
// member of type XmlSerializerNamespaces decorated with the 
// XmlNamespacesDeclarationAttribute, then the XmlSerializer will utilize those
// namespaces during serialization.
public MyTypeWithNamespaces( )
{
    this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
        new XmlQualifiedName(string.Empty, "urn:Abracadabra") // Default Namespace
    });
}

[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces
{
    get { return this._namespaces; }
}
private XmlSerializerNamespaces _namespaces;

তারপরে, পরে আপনার কোডে যা MyTypeWithNamespacesবস্তুটি এটি সিরিয়ালায়িত করতে ব্যবহার করে আপনি এটিকে আমার উপরের মতো কল করবেন:

MyTypeWithNamespaces myType = new MyTypeWithNamespaces("myLabel", 42);

XmlSerializer xs = new XmlSerializer(typeof(MyTypeWithNamespaces),
    new XmlRootAttribute("MyTypeWithNamespaces") { Namespace="urn:Abracadabra" });

...

// Above, you'd setup your XmlTextWriter.

// Now serialize our object.
xs.Serialize(xtw, myType, myType.Namespaces);

এবং XmlSerializerআউটপুটে কোনও অতিরিক্ত নেমস্পেস ছাড়াই উপরে উল্লিখিত একই এক্সএমএলটিকে আবার ফিরিয়ে ফেলবে:

<MyTypeWithNamespaces>
    <Label>myLabel<Label>
    <Epoch>42</Epoch>
</MyTypeWithNamespaces>

সম্পূর্ণতার জন্য, সম্ভবত আপনার এখানে সঠিক উত্তর উল্লেখ করার পরিবর্তে সঠিক উত্তরটি অন্তর্ভুক্ত করা উচিত, এবং এটির 'অসমর্থিত আচরণ' বলে আপনি কীভাবে সিদ্ধান্তে পৌঁছেছেন তা জানতে আগ্রহী।
ডেভ ভ্যান ডেন এ্যান্ডে

1
এটি পরীক্ষা করতে আবার এখানে এসেছেন, যেহেতু এটি আমার সর্বাধিক সহজ ব্যাখ্যা explanation ধন্যবাদ @ ফোরপাস্টমিডনাইট
আন্দ্রে আলবুকার্ক

2
আমি এটি পাই না, আপনার চূড়ান্ত ওপি-র উত্তরের জন্য, আপনি এখনও সিরিয়ালাইজেশন "urn: Abracadabra" (কনস্ট্রাক্টর) এর সময় একটি নেমস্পেস ব্যবহার করছেন, কেন এটি চূড়ান্ত ফলাফলের অন্তর্ভুক্ত নয়। ওপি ব্যবহার করা উচিত নয়: এক্সএমএসআরশায়ালাইজারসাম্পেসিটি এমটিএক্সএমএলসিরাইজারনেমস্পেসেস = নতুন এক্সএমএলসিরিয়ালাইজারনেসস্পেসেস (নতুন [] {এক্সএমএলকিউলিফাইডনেম.এম্পটি});
dparkar

2
এটি সঠিক উত্তর, যদিও সবচেয়ে বেশি ভোট দেওয়া হয়নি। আমার পক্ষে কাজ করার মতো কাজটি হ'ল আমাকে XmlTextWriter xtw = (XmlTextWriter)XmlTextWriter.Create(ms, xws);প্রতিস্থাপন করতে হবে var xtw = XmlTextWriter.Create(memStm, xws);
লিওনেল সানচা দা সিলভা

1
আমি এই উত্তরটি লেখার পরে অনেকক্ষণ হয়ে গেল। XmlTextWriter.Createএকটি (বিমূর্ত?) XmlWriterউদাহরণ প্রদান করে। সুতরাং @ প্রেজা 8 সঠিক, আপনি অন্য নির্দিষ্ট XmlTextWriterবৈশিষ্ট্য (কমপক্ষে, এটি ডাউন-কাস্টিং ছাড়াই নয়) সেট করার ক্ষমতা হারাবেন, তাই নির্দিষ্ট কাস্টটিতে XmlTextWriter
ফোরস্পাস্টমিডনাইট

257
//Create our own namespaces for the output
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

//Add an empty namespace and empty value
ns.Add("", "");

//Create the serializer
XmlSerializer slz = new XmlSerializer(someType);

//Serialize the object with our own namespaces (notice the overload)
slz.Serialize(myXmlTextWriter, someObject, ns)

24
হুম ... তোমরা ছেলেরা বিদ্রোহী। এটি এমএসডিএন.মাইক্রোসফটকম /en-us/library/… এ স্পষ্টভাবে বলেছে যে আপনি এটি করতে পারবেন না।
রাল্ফ লাভেল

বুল ইয়াহ! (এমএস কী বলে আপনি কী করতে পারবেন না তার উত্তরণের জন্য)
গ্রানাডা কোডার

3
আমি কেন এটি "অসমর্থিত" তা নিশ্চিত নই তবে আমি যা চেয়েছিলাম ঠিক এটি এটি করে।
ড্যান বেচার্ড

8
এই উত্তরটি "xMLns: d1p1" এবং "xMLns: q1" নামের স্থান তৈরি করে। এটা কি?
লিওনেল সানচা দা সিলভা

2
ঠিক আছে, এই কোডটি অন্য নেমস্পেসের সংজ্ঞা ছাড়াই সত্যই সহজ সিরিয়ালের জন্য কাজ করে। একাধিক নেমস্পেস সংজ্ঞাগুলির জন্য, কার্যকারী উত্তর হ'ল গৃহীত উত্তর।
লিওনেল সান্চস সিলভা

6

বিকল্প আছে - আপনি সিরিয়ালায়িত করার জন্য প্রকারের এক্সএমএলসিরিয়ালাইজারস্পেসেস টাইপের সদস্য সরবরাহ করতে পারেন । এটি XMLNamespaceDeclaration দিয়ে সজ্জিত করুন গুণাবলী । সেই সদস্যটির সাথে নামের স্থানের উপসর্গ এবং ইউআরআই যুক্ত করুন। তারপরে, যে কোনও সিরিয়ালাইজেশন যা স্পষ্টভাবে একটি এক্সএমএলসিরালাইজার নেমস্পেসগুলি সরবরাহ করে না সেগুলি আপনার টাইপের মধ্যে দেওয়া নামস্থান উপসর্গ + ইউআরআই জোড়া ব্যবহার করবে।

উদাহরণ কোড, ধরুন এটি আপনার প্রকার:

[XmlRoot(Namespace = "urn:mycompany.2009")]
public class Person {
  [XmlAttribute] 
  public bool Known;
  [XmlElement]
  public string Name;
  [XmlNamespaceDeclarations]
  public XmlSerializerNamespaces xmlns;
}

তুমি এটি করতে পারো:

var p = new Person
  { 
      Name = "Charley",
      Known = false, 
      xmlns = new XmlSerializerNamespaces()
  }
p.xmlns.Add("",""); // default namespace is emoty
p.xmlns.Add("c", "urn:mycompany.2009");

এবং এর অর্থ হ'ল instance দৃষ্টান্তটির যে কোনও সিরিয়ালাইজেশন যা নিজের উপসর্গের + ইউআরআই জোড়গুলির নিজস্ব সেট নির্দিষ্ট করে না সে "urn: mycompany.2009" নেমস্পেসের জন্য "p" উপসর্গটি ব্যবহার করবে। এটি এক্সসি এবং এক্সএসডি নেমস্পেসগুলি বাদ দেবে।

এখানে পার্থক্যটি হ'ল আপনি এক্সএমএসআরশায়ালার নেমস্পেসগুলি নিজেই টাইপের সাথে যুক্ত করছেন, এটি এক্সএমএসরিশায়ালার.সারিয়ালাইজ () এর কলটিতে স্পষ্টভাবে নিয়োগের চেয়ে। এর অর্থ হ'ল যদি আপনার ধরণের কোনও উদাহরণ আপনার নিজের নয় এমন কোড দ্বারা সিরিয়ালযুক্ত হয় (উদাহরণস্বরূপ কোনও ওয়েবসার্চেস স্ট্যাকের ক্ষেত্রে) এবং সেই কোডটি স্পষ্টভাবে একটি এক্সএমএলসিরাইজারনেসস্পেসেস সরবরাহ করে না, তবে সিরিয়ালটি উদাহরণটিতে প্রদত্ত নেমস্পেসগুলি ব্যবহার করবে।


1. আমি পার্থক্য দেখতে পাচ্ছি না। আপনি এখনও এক্সএমএলসিরিয়ালাইজারনেসস্পেসের একটি দৃষ্টান্তে ডিফল্ট নেমস্পেস যুক্ত করছেন।
ডেভ ভ্যান ডেন এঁয়েডে

3
২. এটি ক্লাসগুলিকে আরও দূষিত করে। আমার উদ্দেশ্যটি নির্দিষ্ট নেমস্পেস ব্যবহার করা নয়, আমার উদ্দেশ্যটি নেমস্পেসগুলি মোটেও ব্যবহার করা নয়।
ডেভ ভ্যান ডেন এঁয়েডে

আমি এই পদ্ধতির মধ্যে পার্থক্য সম্পর্কে একটি নোট যোগ করেছি এবং কেবল সিরিয়ালাইজেশনের সময় এক্সএমএসআরশায়ালাইজার নেমস্পেসগুলি নির্দিষ্ট করেছিলাম।
চিজো

0

আমি ব্যাবহার করছি:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        const string DEFAULT_NAMESPACE = "http://www.something.org/schema";
        var serializer = new XmlSerializer(typeof(Person), DEFAULT_NAMESPACE);
        var namespaces = new XmlSerializerNamespaces();
        namespaces.Add("", DEFAULT_NAMESPACE);

        using (var stream = new MemoryStream())
        {
            var someone = new Person
            {
                FirstName = "Donald",
                LastName = "Duck"
            };
            serializer.Serialize(stream, someone, namespaces);
            stream.Position = 0;
            using (var reader = new StreamReader(stream))
            {
                Console.WriteLine(reader.ReadToEnd());
            }
        }
    }
}

নিম্নলিখিত এক্সএমএল পেতে:

<?xml version="1.0"?>
<Person xmlns="http://www.something.org/schema">
  <FirstName>Donald</FirstName>
  <LastName>Duck</LastName>
</Person>

আপনি যদি নেমস্পেসটি না চান তবে কেবল "" ডিএএফএলএআইডিএলপিএসএসিএসি "সেট করুন।


যদিও এই প্রশ্নটি 10 ​​বছরেরও বেশি পুরনো, ততক্ষণে এটির মূল বিষয়টি ছিল একটি এক্সএমএল বডি যা কোনও নেমস্পেসের ঘোষণায় মোটেই নেই।
ডেভ ভ্যান ডেন এেন্ডে

1
যদি আমি 10 বছরের পুরানো কোনও প্রশ্নের নিজের উত্তর যুক্ত করি তবে এটি হ'ল গ্রহণযোগ্য উত্তরটি সম্পূর্ণ সংস্করণে বাইবেলের চেয়ে বেশি দীর্ঘ পড়তে হবে।
সর্বাধিক

এবং সর্বাধিক ভোট দেওয়া উত্তর এমন একটি পদ্ধতির প্রচার করে (খালি নামস্থান) যা প্রস্তাবিত নয়।
সর্বাধিক

আমি এটা সাহায্য করতে পারি না। আমি বিশ্বাসযোগ্য উত্তরটি কেবলমাত্র সঠিক হিসাবে তৈরি করতে পারি।
ডেভ ভ্যান ডেন এয়েণ্ডে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.