XML-элемент (& ldquo; name & rdquo;) имеет значение null, если задано xmlns (XSD) [duplicate]

tl; dr Если вам действительно нужна операция, используйте groupByKey , как предложено , по @MariusIon . Каждое предлагаемое здесь решение является либо неэффективным, либо, по меньшей мере, субоптимальным по сравнению с прямой группировкой.

reduceByKey с конкатенацией списка не является приемлемым решением, потому что:

  • Требуется инициализация из списков O (N) .
  • Каждое приложение + для пары списков требует полной копии обоих списков ( O (N) ), эффективно увеличивая общую сложность до O (N2) .
  • Не затрагивает ни одну из проблем, введенных в groupByKey. Количество данных, которые необходимо перетасовать, а также размер конечной структуры одинаковы.
  • В отличие от , предложенного одним из ответов , нет разницы в уровне параллелизм между реализацией с использованием reduceByKey и groupByKey.

combineByKey с list.extend является субоптимальным решением, потому что:

  • Создает O (N) в MergeValue (это можно оптимизировать, используя list.append непосредственно в новом элементе).
  • Если оптимизировано с помощью list.append, оно в точности эквивалентно (Spark & ​​lt; = 1.3) реализации groupByKey и игнорирует все оптимизации, введенные SPARK-3074, которые позволяют группировать внешние (на диске) структуры с большими размерами.

77
задан Sadegh 17 July 2009 в 22:06
поделиться

3 ответа

Вместо записи:

nodes.Elements("Foo")

пишите:

nodes.Elements().Where(e => e.Name.LocalName == "Foo")

, и когда вы устали от этого, сделайте свой собственный метод расширения:

public static IEnumerable<XElement> ElementsAnyNS<T>(this IEnumerable<T> source, string localName)
    where T : XContainer
{
    return source.Elements().Where(e => e.Name.LocalName == localName);
}

То же для атрибутов, если вам приходится часто обращаться с именами атрибутов (что относительно редко).

[EDIT] Добавление решения для XPath

Для XPath вместо написания :

/foo/bar | /foo/ns:bar | /ns:foo/bar | /ns:foo/ns:bar

вы можете использовать функцию local-name():

/*[local-name() = 'foo']/*[local-name() = 'bar']
125
ответ дан Pavel Minaev 26 August 2018 в 18:17
поделиться
  • 1
    Это, безусловно, решает половину моей проблемы. Но как мне это сделать с выражениями XPath? – Jonathan Allen 20 July 2009 в 19:02
  • 2
    См. Обновленный ответ. – Pavel Minaev 20 July 2009 в 22:29
  • 3
    Если вы знаете, что элемент, который вы хотите, имеет уникальное имя, вы можете пропустить все промежуточные элементы с помощью: xDoc.Root.Descendants().Where(e => e.Name.LocalName == "SomeName"); – AaronLS 24 April 2014 в 21:07

Ниже приведен метод разделения пространств имен:

private static XElement StripNamespaces(XElement rootElement)
{
    foreach (var element in rootElement.DescendantsAndSelf())
    {
        // update element name if a namespace is available
        if (element.Name.Namespace != XNamespace.None)
        {
            element.Name = XNamespace.None.GetName(element.Name.LocalName);
        }

        // check if the element contains attributes with defined namespaces (ignore xml and empty namespaces)
        bool hasDefinedNamespaces = element.Attributes().Any(attribute => attribute.IsNamespaceDeclaration ||
                (attribute.Name.Namespace != XNamespace.None && attribute.Name.Namespace != XNamespace.Xml));

        if (hasDefinedNamespaces)
        {
            // ignore attributes with a namespace declaration
            // strip namespace from attributes with defined namespaces, ignore xml / empty namespaces
            // xml namespace is ignored to retain the space preserve attribute
            var attributes = element.Attributes()
                                    .Where(attribute => !attribute.IsNamespaceDeclaration)
                                    .Select(attribute =>
                                        (attribute.Name.Namespace != XNamespace.None && attribute.Name.Namespace != XNamespace.Xml) ?
                                            new XAttribute(XNamespace.None.GetName(attribute.Name.LocalName), attribute.Value) :
                                            attribute
                                    );

            // replace with attributes result
            element.ReplaceAttributes(attributes);
        }
    }
    return rootElement;
}

Пример использования:

XNamespace ns = "http://schemas.domain.com/orders";
XElement xml =
    new XElement(ns + "order",
        new XElement(ns + "customer", "Foo", new XAttribute("hello", "world")),
        new XElement("purchases",
            new XElement(ns + "purchase", "Unicycle", new XAttribute("price", "100.00")),
            new XElement("purchase", "Bicycle"),
            new XElement(ns + "purchase", "Tricycle",
                new XAttribute("price", "300.00"),
                new XAttribute(XNamespace.Xml.GetName("space"), "preserve")
            )
        )
    );

Console.WriteLine(xml.Element("customer") == null);
Console.WriteLine(xml);
StripNamespaces(xml);
Console.WriteLine(xml);
Console.WriteLine(xml.Element("customer").Attribute("hello").Value);
15
ответ дан Ahmad Mageed 26 August 2018 в 18:17
поделиться

Поскольку я нашел этот вопрос в поисках простого способа игнорировать пространства имен в атрибутах, вот расширение для игнорирования пространств имен при доступе к атрибуту на основе ответа Павла (для более легкого копирования я включил его расширение):

public static XAttribute AttributeAnyNS<T>(this T source, string localName)
where T : XElement
{
    return source.Attributes().SingleOrDefault(e => e.Name.LocalName == localName);
}

public static IEnumerable<XElement> ElementsAnyNS<T>(this IEnumerable<T> source, string localName)
where T : XContainer
{
    return source.Elements().Where(e => e.Name.LocalName == localName);
}
4
ответ дан JYelton 26 August 2018 в 18:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: