prosource

XmlSerializer: 불필요한 xsi 및 xsd 네임스페이스 제거

probook 2023. 9. 10. 12:22
반응형

XmlSerializer: 불필요한 xsi 및 xsd 네임스페이스 제거

루트 요소에 기본 네임스페이스를 쓰지 않도록 XmlSerializer를 구성하는 방법이 있습니까?

제가 얻은 것은 다음과 같습니다.

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

그리고 두 xmlns 선언을 모두 삭제하고 싶습니다.

중복:xmlns="…"를 얻지 않고 개체를 XML로 직렬화하는 방법?

//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)

Dave가 에서 객체를 직렬화할 때 모든 xsixsd 네임스페이스를 생략하는 것에 대한 답변을 반복해 달라고 요청했기 때문입니다.NET, 저는 이 게시물을 업데이트했고, 위에 언급한 링크에서 답변을 반복했습니다.이 답변에 사용된 예는 다른 질문에 사용된 예와 같습니다.다음은 복사한 것입니다, 버바텀.


온라인에서 마이크로소프트의 설명서와 몇 가지 해결책을 읽고 이 문제에 대한 해결책을 찾았습니다.내장된 제품과 함께 작동합니다.XmlSerializer를 통해 사용자 정의 XML 직렬화를 수행할 수 있습니다.IXmlSerialiazble.

솔직히 저도 같은 걸로 할게요.MyTypeWithNamespaces지금까지 이 질문에 대한 답변에 사용된 XML 샘플입니다.

[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");

******/

/*****
  Per @dbc, since MyTypeWithNamespaces has a XmlRootAttribute decorating the class,
  You may be able to get away with NOT using this .ctor and use the simple
  XmlSerializer(Type) .ctor.
  Also, be careful not to use serializer creation in loops, as it could lead
  to extensive memory issues due to how serializers are cached (or not...).
  See @dbc's comment and link to SO Q&A for more details.

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

// 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>

저는 최근 프로젝트에서 웹 서비스 호출을 위해 XML로 직렬화된 클래스의 심층 계층 구조로 이 방법을 성공적으로 사용했습니다.마이크로소프트의 문서는 공개적으로 접근할 수 있는 대상을 어떻게 해야 하는지에 대해 명확하지 않습니다.XmlSerializerNamespaces한 번만 만들어도 소용없다고 생각하는 멤버들이 많습니다.그러나 이들의 설명서를 따르고 위에 표시된 방식으로 사용하면 지원되지 않는 동작이나 구현을 통해 "롤링" 직렬화를 수행하지 않고도 XmlSerializer가 클래스에 맞게 XML을 생성하는 방법을 사용자 정의할 수 있습니다.IXmlSerializable.

나는 이 대답이 어떻게 하면 표준을 없앨 수 있을지에 대해 완전히 잠재울 수 있기를 희망합니다.xsi그리고.xsd에 의해 생성된 네임스페이스XmlSerializer.

업데이트: 모든 네임스페이스를 제거하는 것에 대한 OP의 질문에 답했는지 확인하고 싶습니다.위의 제 코드가 이에 적합할 것입니다. 방법을 보여드리겠습니다.위의 예제에서는 두 개의 네임스페이스가 사용되고 있기 때문에 실제로 모든 네임스페이스를 제거할 수 없습니다.XML 문서 어딘가에 다음과 같은 것이 필요할 것입니다.xmlns="urn:Abracadabra" xmlns:w="urn:Whoohoo더문서의 , 위에 ( 둘 다) 둘. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Abracadbra그리고.Whoohoo두 중 둘 요소를 가 두 개안 그렇지 않으면 두 네임스페이스 중 하나 또는 둘 다에 있는 요소를 일종의 접두사로 장식해야 합니다(기본 네임스페이스가 두 개 있으면 안 되죠?).이 어,,,Abracadabra는 기본 네임스페이스입니다.나는 내 안에 있을 수 있습니다.MyTypeWithNamespaces 클래스에 스사가에가사스srWhoohoo네임스페이스는 다음과 같습니다.

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이름 칸


이것으로 다른 질문에 대한 제 답변을 마칩니다.하지만 저는 이름 공간을 사용하지 않는 것에 대한 OP의 질문에 답을 했는지 확인하고 싶었습니다. 아직까지는 이 문제에 대해 제대로 다루지 않았다고 생각하기 때문입니다.라고 가정합니다.<Label>이며, 이이우와한의다의다의한st와sfn이e우s의e,eurn: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출력에 추가 네임스페이스가 없이 바로 위에 표시된 것과 동일한 XML을 다시 뱉습니다.

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

사용 중:

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을 가져오려면 다음과 같이 하십시오.

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

네임스페이스를 사용하지 않으려면 DEFAULT_NAMESpace를 ""로 설정하면 됩니다.

다른 방법이 있습니다. 직렬화할 형식으로 XmlSerializerNamespaces 형식의 멤버를 제공할 수 있습니다.XmlNamespaceDeclarations 특성으로 장식합니다.네임스페이스 접두사와 URI를 해당 멤버에 추가합니다.그러면 XmlSerializerNamespaces를 명시적으로 제공하지 않는 모든 직렬화는 네임스페이스 접두사+를 사용합니다.유형에 입력한 URI 쌍입니다.

예를 들어, 이것이 당신의 타입이라고 가정해 보겠습니다.

[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");

그리고 그것은 그 인스턴스의 직렬화가 자신의 접두사 집합을 지정하지 않는 것을 의미할 것입니다.URI 쌍은 "urn:mycompany.2009" 네임스페이스에 "p" 접두사를 사용합니다.또한 xsi 및 xsd 네임스페이스도 생략합니다.

여기서 차이점은 XmlSerializerNamespaces를 XmlSerializer 호출에 명시적으로 사용하는 것이 아니라 유형 자체에 XmlSerializerNamespaces를 추가한다는 것입니다.serialize().즉, 사용자 유형의 인스턴스가 소유하지 않은 코드(예: 웹 서비스 스택)로 직렬화되고 해당 코드가 XmlSerializerNamespaces를 명시적으로 제공하지 않는 경우 해당 직렬화기는 인스턴스에 제공된 네임스페이스를 사용합니다.

더럽다는 것은 알지만, 저는 쓰레기를 없애기 위해 레젝스를 사용하는 것만으로도 효과가 있습니다.저는 단지 xmlns를 원하지 않습니다. XML을 일반 JSON과 같이 취급하고 싶습니다.다른 대답들은 의식이 너무 많습니다.

그래서 객체를 직렬화한 후 다음과 같은 작업을 수행합니다.

string xml = "<string xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">Hello, world!</string>";
xml = Regex.Replace(x, @" xmlns:.*?"".*?""", "");

언급URL : https://stackoverflow.com/questions/760262/xmlserializer-remove-unnecessary-xsi-and-xsd-namespaces

반응형