Это кажется ошибкой с CamelCasePropertyNamesContractResolver
. Его базовый класс DefaultContractResolver
имеет два конструктора: конструктор без параметров и версию DefaultContractResolver (Boolean)
(только что устаревшие в Json. NET 7.0). Этот параметр имеет следующее значение:
shareCache
blockquote>
- Тип: System.Boolean Если установлено значение true,
DefaultContractResolver
будет использовать кешированный общий доступ с другими преобразователями тот же тип. Совместное использование кеша значительно улучшит производительность с помощью нескольких экземпляров resolver, потому что дорогое отражение произойдет только один раз. Этот параметр может вызвать неожиданное поведение, если разные экземпляры резольвера предполагают получение разных результатов. Если установлено значение false, настоятельно рекомендуется повторно использовать экземплярыDefaultContractResolver
с помощьюJsonSerializer
.По умолчанию
false
.К сожалению, конструктор по умолчанию для
CamelCasePropertyNamesContractResolver
устанавливает значение вtrue
:public class CamelCasePropertyNamesContractResolver : DefaultContractResolver { public CamelCasePropertyNamesContractResolver() #pragma warning disable 612,618 : base(true) #pragma warning restore 612,618 { NamingStrategy = new CamelCaseNamingStrategy { ProcessDictionaryKeys = true, OverrideSpecifiedNames = true }; } }
Кроме того, нет второго конструктора с
shareCache
. Это нарушает вашSpecificFieldsResolver
.В качестве обходного пути вы можете получить свой резольвер из
DefaultContractResolver
и использоватьCamelCaseNamingStrategy
для отображения имени:public class IndependentCamelCasePropertyNamesContractResolver : DefaultContractResolver { public IndependentCamelCasePropertyNamesContractResolver() : base() { NamingStrategy = new CamelCaseNamingStrategy { ProcessDictionaryKeys = true, OverrideSpecifiedNames = true }; } } public class SpecificFieldsResolver : IndependentCamelCasePropertyNamesContractResolver { // Remainder unchanged }
Обратите внимание, что если вы используете версию Json.NET до 9.0,
CamelCaseNamingStrategy
не существует. Вместо этого вложенное kludgeCamelCasePropertyNamesContractResolver
можно использовать для сопоставления имен:public class IndependentCamelCasePropertyNamesContractResolver : DefaultContractResolver { class CamelCaseNameMapper : CamelCasePropertyNamesContractResolver { // Purely to make the protected method public. public string ToCamelCase(string propertyName) { return ResolvePropertyName(propertyName); } } readonly CamelCaseNameMapper nameMapper = new CamelCaseNameMapper(); protected override string ResolvePropertyName(string propertyName) { return nameMapper.ToCamelCase(propertyName); } }
В примере Вы представляете единственную создаваемую вещь, атрибут...
XmlElement element = (XmlElement)doc.SelectSingleNode("/feed/entry/content");
if (element != null)
element.SetAttribute("source", "");
, Если то, что Вы действительно хотите, должно смочь создать иерархию, где она не существует затем, Вы могли свой собственный простой xpath синтаксический анализатор. Я не знаю о хранении атрибута в xpath все же. Я скорее снял узел в качестве элемента и гвоздя на.SetAttribute, поскольку я сделал здесь:
static private XmlNode makeXPath(XmlDocument doc, string xpath)
{
return makeXPath(doc, doc as XmlNode, xpath);
}
static private XmlNode makeXPath(XmlDocument doc, XmlNode parent, string xpath)
{
// grab the next node name in the xpath; or return parent if empty
string[] partsOfXPath = xpath.Trim('/').Split('/');
string nextNodeInXPath = partsOfXPath.First();
if (string.IsNullOrEmpty(nextNodeInXPath))
return parent;
// get or create the node from the name
XmlNode node = parent.SelectSingleNode(nextNodeInXPath);
if (node == null)
node = parent.AppendChild(doc.CreateElement(nextNodeInXPath));
// rejoin the remainder of the array as an xpath expression and recurse
string rest = String.Join("/", partsOfXPath.Skip(1).ToArray());
return makeXPath(doc, node, rest);
}
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml("<feed />");
makeXPath(doc, "/feed/entry/data");
XmlElement contentElement = (XmlElement)makeXPath(doc, "/feed/entry/content");
contentElement.SetAttribute("source", "");
Console.WriteLine(doc.OuterXml);
}
Немного молчаливо, но это сработает:
>>> class BankAccount(object): pass
...
>>> class SavingsAccount(BankAccount): pass
...
>>> class CheckingAccount(BankAccount): pass
...
>>> x = SavingsAccount()
>>> type(x) == type(SavingsAccount())
True
>>> type(x) == type(CheckingAccount())
False
-121--2995468- Я установил 2010 с 2008 на этой машине для разработки серебряного света.. Я не заметил никаких проблем, кроме ассоциаций файлов все перейти к версии 2010, а не то, что я предпочел бы открыть в 2008 по умолчанию. (2010 год для меня намного медленнее 2008 года)
-121--2666441-Если последовательность XPath обрабатывается с обратной стороны на передний, ее проще обрабатывать без корней XPath, например .//a/b/c... Он также должен поддерживать синтаксис XPath Гордона, хотя я не пытался...
static private XmlNode makeXPath(XmlDocument doc, string xpath)
{
string[] partsOfXPath = xpath.Split('/');
XmlNode node = null;
for (int xpathPos = partsOfXPath.Length; xpathPos > 0; xpathPos--)
{
string subXpath = string.Join("/", partsOfXPath, 0, xpathPos);
node = doc.SelectSingleNode(subXpath);
if (node != null)
{
// append new descendants
for (int newXpathPos = xpathPos; newXpathPos < partsOfXPath.Length; newXpathPos++)
{
node = node.AppendChild(doc.CreateElement(partsOfXPath[newXpathPos]));
}
break;
}
}
return node;
}
Вот моя версия. Надеюсь, это тоже кому-нибудь поможет.
public static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();
XmlNode rootNode = GenerateXPathXmlElements(doc, "/RootNode/FirstChild/SecondChild/ThirdChild");
Console.Write(rootNode.OuterXml);
}
private static XmlDocument GenerateXPathXmlElements(XmlDocument xmlDocument, string xpath)
{
XmlNode parentNode = xmlDocument;
if (xmlDocument != null && !string.IsNullOrEmpty(xpath))
{
string[] partsOfXPath = xpath.Split('/');
string xPathSoFar = string.Empty;
foreach (string xPathElement in partsOfXPath)
{
if(string.IsNullOrEmpty(xPathElement))
continue;
xPathSoFar += "/" + xPathElement.Trim();
XmlNode childNode = xmlDocument.SelectSingleNode(xPathSoFar);
if(childNode == null)
{
childNode = xmlDocument.CreateElement(xPathElement);
}
parentNode.AppendChild(childNode);
parentNode = childNode;
}
}
return xmlDocument;
}
Вот мой быстрый хак, который также может создавать атрибуты, если вы используете формат вроде /configuration/appSettings/add[@key='name']/@value
.
static XmlNode createXPath(XmlDocument doc, string xpath)
{
XmlNode node=doc;
foreach (string part in xpath.Substring(1).Split('/'))
{
XmlNodeList nodes=node.SelectNodes(part);
if (nodes.Count>1) throw new ComponentException("Xpath '"+xpath+"' was not found multiple times!");
else if (nodes.Count==1) { node=nodes[0]; continue; }
if (part.StartsWith("@"))
{
var anode=doc.CreateAttribute(part.Substring(1));
node.Attributes.Append(anode);
node=anode;
}
else
{
string elName, attrib=null;
if (part.Contains("["))
{
part.SplitOnce("[", out elName, out attrib);
if (!attrib.EndsWith("]")) throw new ComponentException("Unsupported XPath (missing ]): "+part);
attrib=attrib.Substring(0, attrib.Length-1);
}
else elName=part;
XmlNode next=doc.CreateElement(elName);
node.AppendChild(next);
node=next;
if (attrib!=null)
{
if (!attrib.StartsWith("@")) throw new ComponentException("Unsupported XPath attrib (missing @): "+part);
string name, value;
attrib.Substring(1).SplitOnce("='", out name, out value);
if (string.IsNullOrEmpty(value) || !value.EndsWith("'")) throw new ComponentException("Unsupported XPath attrib: "+part);
value=value.Substring(0, value.Length-1);
var anode=doc.CreateAttribute(name);
anode.Value=value;
node.Attributes.Append(anode);
}
}
}
return node;
}
SplitOnce - метод расширения:
public static void SplitOnce(this string value, string separator, out string part1, out string part2)
{
if (value!=null)
{
int idx=value.IndexOf(separator);
if (idx>=0)
{
part1=value.Substring(0, idx);
part2=value.Substring(idx+separator.Length);
}
else
{
part1=value;
part2=null;
}
}
else
{
part1="";
part2=null;
}
}
Пример:
public static void Set(XmlDocument doc, string xpath, string value)
{
if (doc==null) throw new ArgumentNullException("doc");
if (string.IsNullOrEmpty(xpath)) throw new ArgumentNullException("xpath");
XmlNodeList nodes=doc.SelectNodes(xpath);
if (nodes.Count>1) throw new ComponentException("Xpath '"+xpath+"' was not found multiple times!");
else if (nodes.Count==0) createXPath(doc, xpath).InnerText=value;
else nodes[0].InnerText=value;
}
например,
Set(doc, "/configuration/appSettings/add[@key='Server']/@value", "foobar");
Мне понравилась версия Криса, потому что она обрабатывала атрибуты в xpaths, а другие решения - нет (хотя она не обрабатывает "text ()" в пути, что я исправил). К сожалению, мне пришлось использовать это в приложении VB, поэтому вот преобразование для этого:
Private Sub SplitOnce(ByVal value As String, ByVal separator As String, ByRef part1 As String, ByRef part2 As String)
If (value IsNot Nothing) Then
Dim idx As Integer = value.IndexOf(separator)
If (idx >= 0) Then
part1 = value.Substring(0, idx)
part2 = value.Substring(idx + separator.Length)
Else
part1 = value
part2 = Nothing
End If
Else
part1 = ""
part2 = Nothing
End If
End Sub
Private Function createXPath(ByVal doc As XmlDocument, ByVal xpath As String) As XmlNode
Dim node As XmlNode = doc
Dim part As String
For Each part In xpath.Substring(1).Split("/")
Dim nodes As XmlNodeList = node.SelectNodes(part)
If (nodes.Count > 1) Then
Throw New Exception("Xpath '" + xpath + "' was not found multiple times!")
ElseIf (nodes.Count = 1) Then
node = nodes(0)
Continue For
End If
If (part.EndsWith("text()")) Then
' treat this the same as previous node since this is really innertext
Exit For
ElseIf (part.StartsWith("@")) Then
Dim anode As XmlAttribute = doc.CreateAttribute(part.Substring(1))
node.Attributes.Append(anode)
node = anode
Else
Dim elName As String = Nothing
Dim attrib As String = Nothing
If (part.Contains("[")) Then
SplitOnce(part, "[", elName, attrib)
If (Not attrib.EndsWith("]")) Then
Throw New Exception("Unsupported XPath (missing ]): " + part)
End If
attrib = attrib.Substring(0, attrib.Length - 1)
Else
elName = part
End If
Dim nextnode As XmlNode = doc.CreateElement(elName)
node.AppendChild(nextnode)
node = nextnode
If (attrib IsNot Nothing) Then
If (Not attrib.StartsWith("@")) Then
Throw New Exception("Unsupported XPath attrib (missing @): " + part)
End If
Dim name As String = ""
Dim value As String = ""
SplitOnce(attrib.Substring(1), "='", name, value)
If (String.IsNullOrEmpty(value) Or Not value.EndsWith("'")) Then
Throw New Exception("Unsupported XPath attrib: " + part)
End If
value = value.Substring(0, value.Length - 1)
Dim anode As XmlAttribute = doc.CreateAttribute(name)
anode.Value = value
node.Attributes.Append(anode)
End If
End If
Next
Return node
End Function