File: XPathQueryGenerator.cs

package info (click to toggle)
mono 6.8.0.105%2Bdfsg-3.3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,284,512 kB
  • sloc: cs: 11,172,132; xml: 2,850,069; ansic: 671,653; cpp: 122,091; perl: 59,366; javascript: 30,841; asm: 22,168; makefile: 20,093; sh: 15,020; python: 4,827; pascal: 925; sql: 859; sed: 16; php: 1
file content (150 lines) | stat: -rw-r--r-- 5,918 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
namespace System.Runtime.Serialization
{
    using System;
    using System.Text;
    using System.Reflection;
    using System.Globalization;
    using System.Collections.Generic;
    using System.Xml;

    public static class XPathQueryGenerator
    {
        const string XPathSeparator = "/";
        const string NsSeparator = ":";

        public static string CreateFromDataContractSerializer(Type type, MemberInfo[] pathToMember, out XmlNamespaceManager namespaces)
        {
            return CreateFromDataContractSerializer(type, pathToMember, null, out namespaces);
        }

        // Here you can provide your own root element Xpath which will replace the Xpath of the top level element
        public static string CreateFromDataContractSerializer(Type type, MemberInfo[] pathToMember, StringBuilder rootElementXpath, out XmlNamespaceManager namespaces)
        {
            if (type == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("type"));
            }
            if (pathToMember == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("pathToMember"));
            }

            DataContract currentContract = DataContract.GetDataContract(type);
            ExportContext context;

            if (rootElementXpath == null)
            {
                context = new ExportContext(currentContract);
            }
            else
            {
                // use the provided xpath for top level element
                context = new ExportContext(rootElementXpath);
            }

            for (int pathToMemberIndex = 0; pathToMemberIndex < pathToMember.Length; pathToMemberIndex++)
            {
                currentContract = ProcessDataContract(currentContract, context, pathToMember[pathToMemberIndex]);
            }

            namespaces = context.Namespaces;
            return context.XPath;
        }

        static DataContract ProcessDataContract(DataContract contract, ExportContext context, MemberInfo memberNode)
        {
            if (contract is ClassDataContract)
            {
                return ProcessClassDataContract((ClassDataContract)contract, context, memberNode);
            }
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.QueryGeneratorPathToMemberNotFound)));
        }

        static DataContract ProcessClassDataContract(ClassDataContract contract, ExportContext context, MemberInfo memberNode)
        {
            string prefix = context.SetNamespace(contract.Namespace.Value);
            foreach (DataMember member in GetDataMembers(contract))
            {
                if (member.MemberInfo.Name == memberNode.Name && member.MemberInfo.DeclaringType.IsAssignableFrom(memberNode.DeclaringType))
                {
                    context.WriteChildToContext(member, prefix);
                    return member.MemberTypeContract;
                }
            }
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.QueryGeneratorPathToMemberNotFound)));
        }

        static IEnumerable<DataMember> GetDataMembers(ClassDataContract contract)
        {
            if (contract.BaseContract != null)
            {
                foreach (DataMember baseClassMember in GetDataMembers(contract.BaseContract))
                {
                    yield return baseClassMember;
                }
            }
            if (contract.Members != null)
            {
                foreach (DataMember member in contract.Members)
                {
                    yield return member;
                }
            }
        }

        class ExportContext
        {
            XmlNamespaceManager namespaces;
            int nextPrefix;
            StringBuilder xPathBuilder;

            public ExportContext(DataContract rootContract)
            {
                this.namespaces = new XmlNamespaceManager(new NameTable());
                string prefix = SetNamespace(rootContract.TopLevelElementNamespace.Value);
                this.xPathBuilder = new StringBuilder(XPathQueryGenerator.XPathSeparator + prefix + XPathQueryGenerator.NsSeparator + rootContract.TopLevelElementName.Value);
            }

            public ExportContext(StringBuilder rootContractXPath)
            {
                this.namespaces = new XmlNamespaceManager(new NameTable());
                this.xPathBuilder = rootContractXPath;
            }

            public void WriteChildToContext(DataMember contextMember, string prefix)
            {
                this.xPathBuilder.Append(XPathQueryGenerator.XPathSeparator + prefix + XPathQueryGenerator.NsSeparator + contextMember.Name);
            }

            public XmlNamespaceManager Namespaces
            {
                get
                {
                    return this.namespaces;
                }
            }

            public string XPath
            {
                get
                {
                    return this.xPathBuilder.ToString();
                }
            }

            public string SetNamespace(string ns)
            {
                string prefix = namespaces.LookupPrefix(ns);
                if (prefix == null || prefix.Length == 0)
                {
                    prefix = "xg" + (this.nextPrefix++).ToString(NumberFormatInfo.InvariantInfo);
                    Namespaces.AddNamespace(prefix, ns);
                }
                return prefix;
            }
        }
    }
}