วิธีป้องกันแอตทริบิวต์ xmlns ว่างในเอาต์พุตจาก XmlDocument ของ. NET


118

เมื่อสร้าง XML จาก XmlDocument ใน. NET xmlnsแอตทริบิวต์เปล่าจะปรากฏขึ้นในครั้งแรกที่มีการแทรกองค์ประกอบที่ไม่มีเนมสเปซที่เกี่ยวข้อง จะป้องกันได้อย่างไร?

ตัวอย่าง:

XmlDocument xml = new XmlDocument();
xml.AppendChild(xml.CreateElement("root",
    "whatever:name-space-1.0"));
xml.DocumentElement.AppendChild(xml.CreateElement("loner"));
Console.WriteLine(xml.OuterXml);

เอาท์พุท:

<root xmlns="whatever:name-space-1.0"><loner xmlns="" /></root>

ผลลัพธ์ที่ต้องการ :

<root xmlns="whatever:name-space-1.0"><loner /></root>

มีวิธีแก้ไขที่ใช้กับXmlDocumentรหัสไม่ใช่สิ่งที่เกิดขึ้นหลังจากการแปลงเอกสารเป็นสตริงด้วยOuterXmlหรือไม่?

เหตุผลของฉันในการทำเช่นนี้คือเพื่อดูว่าฉันสามารถจับคู่ XML มาตรฐานของโปรโตคอลเฉพาะโดยใช้ XML ที่สร้างขึ้นด้วย XmlDocument หรือไม่ xmlnsแอตทริบิวต์ว่างต้องไม่ทำลายหรือสร้างความสับสนให้กับโปรแกรมแยกวิเคราะห์ แต่ก็ไม่มีอยู่ในการใช้งานใด ๆ ที่ฉันเคยเห็นของโปรโตคอลนี้

คำตอบ:


111

ขอบคุณคำตอบของ Jeremy Lew และการเล่นอีกเล็กน้อยฉันจึงคิดหาวิธีลบxmlnsแอตทริบิวต์เปล่า: ส่งผ่านเนมสเปซของโหนดรูทเมื่อสร้างโหนดลูกใด ๆ ที่คุณไม่ต้องการให้มีคำนำหน้า ใช้ namespace โดยไม่มีคำนำหน้าที่หมายถึงรากที่คุณจำเป็นต้องใช้ namespace เดียวกันในองค์ประกอบของเด็กสำหรับพวกเขาจะยังไม่ได้มีคำนำหน้า

รหัสคงที่:

XmlDocument xml = new XmlDocument();
xml.AppendChild(xml.CreateElement("root", "whatever:name-space-1.0"));
xml.DocumentElement.AppendChild(xml.CreateElement("loner", "whatever:name-space-1.0")); 
Console.WriteLine(xml.OuterXml);

ขอบคุณทุกคนสำหรับทุกคำตอบของคุณที่ทำให้ฉันไปในทิศทางที่ถูกต้อง!


1
แม่นยำ. การใส่องค์ประกอบ <loner> ในเนมสเปซ "any: name-space-1.0" หมายความว่าแอตทริบิวต์ xmlns ว่าง (ซึ่งทำให้ไม่มีเนมสเปซ) จะไม่ถูกเพิ่มลงในเนมสเปซ หากคุณต้องการรีเฟรชเกี่ยวกับการทำงานของเนมสเปซให้ดูที่jclark.com/xml/xmlns.htm
JeniT

2
ระวัง: องค์ประกอบต้องการสิ่งนี้ (หรืออาจจะดีกว่าdoc.DocumentElement.NamespaceURI) แต่อย่าระบุเนมสเปซเพื่อให้CreateAttribute()คุณได้รับxmlns:psomethingแม้ว่าจะเป็นยูริเดียวกันก็ตาม
Jason Kleban

87

นี่คือตัวแปรของคำตอบของ JeniT (ขอบคุณมาก btw!)

XmlElement new_element = doc.CreateElement("Foo", doc.DocumentElement.NamespaceURI);

ซึ่งจะช่วยลดการคัดลอกหรือทำเนมสเปซซ้ำทุกที่


3
คำตอบที่ดีที่สุดตามฉัน เราไม่จำเป็นต้องรู้ว่าเนมสเปซเริ่มต้นของเอกสารคืออะไร (มีประโยชน์เมื่อเราไม่สร้างไฟล์ xml ตั้งแต่เริ่มต้นเช่นในสถานการณ์อ่านและแก้ไข)
MuiBienCarlota

11

หาก<loner>องค์ประกอบใน XML ตัวอย่างของคุณไม่มีการxmlnsประกาศเนมสเปซเริ่มต้นองค์ประกอบนั้นจะอยู่ในwhatever:name-space-1.0เนมสเปซแทนที่จะอยู่ในเนมสเปซ หากนั่นคือสิ่งที่คุณต้องการคุณต้องสร้างองค์ประกอบในเนมสเปซนั้น:

xml.CreateElement("loner", "whatever:name-space-1.0")

หากคุณต้องการให้<loner>องค์ประกอบไม่มีเนมสเปซ XML ที่สร้างขึ้นก็เป็นสิ่งที่คุณต้องการและคุณไม่ควรกังวลเกี่ยวกับxmlnsแอตทริบิวต์ที่ถูกเพิ่มโดยอัตโนมัติสำหรับคุณ


3
ปัญหาเกิดจากตัวแยกวิเคราะห์ XML ที่ไม่เป็นไปตามข้อกำหนด (โดยทั่วไปจาก Microsoft) ซึ่งไม่สามารถจัดการกับ xmnls = "")
Craig Trader

2
/ เรียกว่า พวกเขาต้องการความคิดเห็นทุบตี MS แบบสุ่มกลับ

@W Craig Trader - ไม่สามารถพูดได้ว่าฉันพบว่าเป็นปัญหา ตัวอย่าง?
Kev

1
ถูกต้องฉันไม่ต้องการให้โหนด <loner /> มีเนมสเปซ แต่ฉันไม่ต้องการให้มีแอตทริบิวต์เนมสเปซว่าง (xmlns) ด้วย เหตุผลของฉันคือเพื่อดูว่าฉันสามารถจับคู่เอาต์พุต XML ของโปรโตคอลเฉพาะที่ตั้งค่าเช่นนี้ได้หรือไม่
Neil C. Obremski

5
มันไม่ใช่การทุบตีแบบสุ่ม Microsoft Updater Application Block ใช้ XML Manifest เพื่อกำหนดสิ่งที่จะส่งมอบให้กับไคลเอ็นต์ น่าเสียดายที่โปรแกรมแยกวิเคราะห์ Manifest ไม่สามารถรับมือกับ xmlns = ""; ฉันต้องเขียนโพสต์โปรเซสเซอร์ที่จะดึงแอตทริบิวต์ xmlns ว่างออก
Craig Trader

7

เนื่องจากรูทอยู่ในเนมสเปซที่ไม่ได้เติมคำนำหน้าจึงต้องมีเอาต์พุตย่อยของรูทที่ต้องการยกเลิกเนมสเปซเช่นเดียวกับตัวอย่างของคุณ วิธีแก้ปัญหาคือนำหน้าองค์ประกอบรากดังนี้:

<w:root xmlns:w="whatever:name-space-1.0">
   <loner/>
</w:root>

รหัส:

XmlDocument doc = new XmlDocument();
XmlElement root = doc.CreateElement( "w", "root", "whatever:name-space-1.0" );
doc.AppendChild( root );
root.AppendChild( doc.CreateElement( "loner" ) );
Console.WriteLine(doc.OuterXml);

ขอบคุณ แต่การเพิ่มเนมสเปซไปยังรูทจริงจะทำให้ XML ของฉันเสียหายโดยสัมพันธ์กับโปรโตคอลเฉพาะที่ฉันใช้งาน
Neil C. Obremski

อา! ฉันตระหนักมากขึ้นในสิ่งที่คุณพูดและนำมาพิจารณาเมื่อเขียนคำตอบของฉันเอง ขอบคุณ Jeremy
Neil C. Obremski

0

ถ้าเป็นไปได้ให้สร้างคลาสการทำให้เป็นอนุกรมจากนั้นทำ:

XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlSerializer serializer = new XmlSerializer(yourType);
serializer.Serialize(xmlTextWriter, someObject, ns);

ปลอดภัยกว่าและคุณสามารถควบคุมเนมสเปซด้วยแอตทริบิวต์ได้หากต้องการการควบคุมมากขึ้น


0

ฉันได้แก้ปัญหาโดยใช้รูปแบบโรงงาน ฉันสร้างโรงงานสำหรับวัตถุ XElement เป็นพารามิเตอร์สำหรับการสร้างอินสแตนซ์ของโรงงานฉันได้ระบุวัตถุ XNamespace ดังนั้นทุกครั้งที่ XElement ถูกสร้างขึ้นโดยโรงงานเนมสเปซจะถูกเพิ่มโดยอัตโนมัติ นี่คือรหัสของโรงงาน:

internal class XElementFactory
{
    private readonly XNamespace currentNs;

    public XElementFactory(XNamespace ns)
    {
        this.currentNs = ns;
    }

    internal XElement CreateXElement(String name, params object[] content)
    {
        return new XElement(currentNs + name, content);
    }
}

1
สหกรณ์ถูกถามเกี่ยวกับการไม่ได้XmlDocument XDocument
John Saunders

0

ใช่คุณสามารถป้องกัน XMLNS จาก XmlElement เวลาสร้างครั้งแรกที่กำลังจะมา: เช่นนั้น

<trkpt lat="30.53597" lon="-97.753324" xmlns="">
    <ele>249.118774</ele>
    <time>2006-05-05T14:34:44Z</time>
</trkpt>

เปลี่ยนรหัส: และส่งเนมสเปซ xml เช่นนี้

รหัส C #:

XmlElement bookElement = xdoc.CreateElement("trkpt", "http://www.topografix.com/GPX/1/1");
bookElement.SetAttribute("lat", "30.53597");
bookElement.SetAttribute("lon", "97.753324");
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.