ฉันจะมี LINQ เป็น XML iqnore เนมสเปซทั้งหมดได้อย่างไร หรือในทางกลับกันฉันจะตัดเนมสเปซออกได้อย่างไร
ฉันถามเพราะเนมสเปซถูกตั้งค่าแบบกึ่งสุ่มและฉันเบื่อที่จะต้องค้นหาโหนดทั้งที่มีและไม่มีเนมสเปซ
ฉันจะมี LINQ เป็น XML iqnore เนมสเปซทั้งหมดได้อย่างไร หรือในทางกลับกันฉันจะตัดเนมสเปซออกได้อย่างไร
ฉันถามเพราะเนมสเปซถูกตั้งค่าแบบกึ่งสุ่มและฉันเบื่อที่จะต้องค้นหาโหนดทั้งที่มีและไม่มีเนมสเปซ
คำตอบ:
แทนที่จะเขียน:
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);
}
สำหรับแอตทริบิวต์หากคุณต้องจัดการกับแอตทริบิวต์เนมสเปซบ่อยๆ (ซึ่งค่อนข้างหายาก)
สำหรับ XPath แทนที่จะเขียน:
/foo/bar | /foo/ns:bar | /ns:foo/bar | /ns:foo/ns:bar
คุณสามารถใช้local-name()
ฟังก์ชัน:
/*[local-name() = 'foo']/*[local-name() = 'bar']
xDoc.Root.Descendants().Where(e => e.Name.LocalName == "SomeName");
นี่คือวิธีการแถบเนมสเปซ:
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);
เมื่อฉันพบคำถามนี้ในการค้นหาวิธีง่ายๆในการละเว้นเนมสเปซในแอตทริบิวต์ต่อไปนี้เป็นส่วนขยายสำหรับการละเว้นเนมสเปซเมื่อเข้าถึงแอตทริบิวต์ตามคำตอบของ Pavel (เพื่อการคัดลอกที่ง่ายขึ้นฉันรวมส่วนขยายของเขาไว้ด้วย):
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);
}