Теперь вы можете использовать java 8:
Collections.addAll(list, arr);
Collections.shuffle(list);
cardsList.toArray(arr);
Методы расширений:
public static class XExtensions
{
/// <summary>
/// Get the absolute XPath to a given XElement
/// (e.g. "/people/person[6]/name[1]/last[1]").
/// </summary>
public static string GetAbsoluteXPath(this XElement element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
Func<XElement, string> relativeXPath = e =>
{
int index = e.IndexPosition();
string name = e.Name.LocalName;
// If the element is the root, no index is required
return (index == -1) ? "/" + name : string.Format
(
"/{0}[{1}]",
name,
index.ToString()
);
};
var ancestors = from e in element.Ancestors()
select relativeXPath(e);
return string.Concat(ancestors.Reverse().ToArray()) +
relativeXPath(element);
}
/// <summary>
/// Get the index of the given XElement relative to its
/// siblings with identical names. If the given element is
/// the root, -1 is returned.
/// </summary>
/// <param name="element">
/// The element to get the index of.
/// </param>
public static int IndexPosition(this XElement element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
if (element.Parent == null)
{
return -1;
}
int i = 1; // Indexes for nodes start at 1, not 0
foreach (var sibling in element.Parent.Elements(element.Name))
{
if (sibling == element)
{
return i;
}
i++;
}
throw new InvalidOperationException
("element has been removed from its parent.");
}
}
И тест:
class Program
{
static void Main(string[] args)
{
Program.Process(XDocument.Load(@"C:\test.xml").Root);
Console.Read();
}
static void Process(XElement element)
{
if (!element.HasElements)
{
Console.WriteLine(element.GetAbsoluteXPath());
}
else
{
foreach (XElement child in element.Elements())
{
Process(child);
}
}
}
}
И демонстрационный вывод:
/tests/test[1]/date[1]
/tests/test[1]/time[1]/start[1]
/tests/test[1]/time[1]/end[1]
/tests/test[1]/facility[1]/name[1]
/tests/test[1]/facility[1]/website[1]
/tests/test[1]/facility[1]/street[1]
/tests/test[1]/facility[1]/state[1]
/tests/test[1]/facility[1]/city[1]
/tests/test[1]/facility[1]/zip[1]
/tests/test[1]/facility[1]/phone[1]
/tests/test[1]/info[1]
/tests/test[2]/date[1]
/tests/test[2]/time[1]/start[1]
/tests/test[2]/time[1]/end[1]
/tests/test[2]/facility[1]/name[1]
/tests/test[2]/facility[1]/website[1]
/tests/test[2]/facility[1]/street[1]
/tests/test[2]/facility[1]/state[1]
/tests/test[2]/facility[1]/city[1]
/tests/test[2]/facility[1]/zip[1]
/tests/test[2]/facility[1]/phone[1]
/tests/test[2]/info[1]
, Который должен уладить это. Нет?
Может быть несколько xpaths, которые приводят к тому же элементу, таким образом находя самый простой xpath, который приводит к узлу, не тривиально.
Однако довольно легко найти xpath к узлу. Просто повысьте дерева узла, пока Вы не читаете корневой узел и комбинируете имена узла, и у Вас есть допустимый xpath.
При поиске чего-то исходно обеспеченного.NET, ответ нет. Необходимо было бы записать собственный дополнительный метод, чтобы сделать это.
"Полным xpath" я предполагаю, что Вы имеете в виду простую цепочку тегов начиная с количества xpaths, который мог потенциально соответствовать любому элементу, мог быть очень большие.
проблема здесь состоит в том, что очень трудно, если не специфически невозможный создать кого-либо данного xpath, который обратимо проследит до того же элемента - который является условием?
, Если "нет" тогда, возможно, Вы могли бы создать запрос рекурсивно цикличным выполнением со ссылкой на элементы тока parentNode. Если "да", то Вы собираетесь быть рассмотрением расширения этого перекрестными ссылками для индексного положения в одноуровневых наборах, referecing подобные ИДЕНТИФИКАТОРУ атрибуты, если они существуют, и это будет очень иждивенцем на Вашем XSD, если общее решение возможно.
Это - на самом деле дубликат этого вопроса. В то время как это не отмечено как ответ, метод в моем ответе на тот вопрос является единственным способом однозначной формулировки XPath к узлу в рамках XML-документа, который будет всегда работать при всех обстоятельствах. (Это также работает на все типы узлов, не просто элементы.)
Как Вы видите, XPath это, продукты ужасны и абстрактны. но это обращается к опасениям, что много отвечающих сторон повысили здесь. Большинство предложений, сделанных здесь, производит XPath, который при использовании для поиска оригинала документа произведет ряд одного или нескольких узлов, который включает целевой узел. Это - это "или больше", это - проблема. Например, если у меня есть представление XML DataSet, наивного XPath к элементу определенного DataRow, /DataSet1/DataTable1
, также возвращает элементы всех других DataRows в DataTable. Вы не можете снять неоднозначность этого, не зная что-то о том, как XML является forumlated (как, есть ли элемент первичного ключа?).
Но /node()[1]/node()[4]/node()[11]
, существует только один узел, который это будет когда-либо возвращать, несмотря ни на что.
Я обновил код Криса, чтобы учесть префиксы пространства имен. Изменяется только метод GetAbsoluteXPath.
public static class XExtensions
{
/// <summary>
/// Get the absolute XPath to a given XElement, including the namespace.
/// (e.g. "/a:people/b:person[6]/c:name[1]/d:last[1]").
/// </summary>
public static string GetAbsoluteXPath(this XElement element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
Func<XElement, string> relativeXPath = e =>
{
int index = e.IndexPosition();
var currentNamespace = e.Name.Namespace;
string name;
if (currentNamespace == null)
{
name = e.Name.LocalName;
}
else
{
string namespacePrefix = e.GetPrefixOfNamespace(currentNamespace);
name = namespacePrefix + ":" + e.Name.LocalName;
}
// If the element is the root, no index is required
return (index == -1) ? "/" + name : string.Format
(
"/{0}[{1}]",
name,
index.ToString()
);
};
var ancestors = from e in element.Ancestors()
select relativeXPath(e);
return string.Concat(ancestors.Reverse().ToArray()) +
relativeXPath(element);
}
/// <summary>
/// Get the index of the given XElement relative to its
/// siblings with identical names. If the given element is
/// the root, -1 is returned.
/// </summary>
/// <param name="element">
/// The element to get the index of.
/// </param>
public static int IndexPosition(this XElement element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
if (element.Parent == null)
{
return -1;
}
int i = 1; // Indexes for nodes start at 1, not 0
foreach (var sibling in element.Parent.Elements(element.Name))
{
if (sibling == element)
{
return i;
}
i++;
}
throw new InvalidOperationException
("element has been removed from its parent.");
}
}