XML-fa alakjának átalakítása (LINQ XML-vé)

Az XML-dokumentumok alakzata az elemnevekre, attribútumnevekre és a hierarchia jellemzőire hivatkozik.

Néha módosítania kell egy XML-dokumentum alakját. Előfordulhat például, hogy egy meglévő XML-dokumentumot egy másik rendszernek kell elküldenie, amely eltérő elem- és attribútumneveket igényel. A dokumentumon végighaladhat, szükség szerint törölheti és átnevezheti az elemeket, de a funkcionális szerkezet használata olvashatóbb és karbantarthatóbb kódot eredményez. A funkcionális építésről további információt a Funkcionális szerkezet című témakörben talál.

A cikkben szereplő első példa megváltoztatja egy XML-dokumentum szervezetét. Összetett elemeket helyez át a fa egyik helyről a másikra.

A második példa létrehoz egy XML-dokumentumot, amelynek alakja eltér a forrásdokumentumétól. Kihagy néhány elemet, átnevez másokat, és módosítja az elemnevek burkolatát.

Példa: Beágyazott lekérdezési kifejezések használata XML-fa alakjának módosításához

Az alábbi példa beágyazott lekérdezési kifejezések használatával módosítja egy XML-fájl alakját.

A példához tartozó forrás XML-dokumentum, minta XML-fájl: Ügyfelek és rendelések, az elem alatt egy Customers olyan elemet tartalmaz, amely az Root összes ügyfelet tartalmazza. Emellett tartalmaz egy Orders elemet is az Root elem alatt, amely az összes rendelést tartalmazza. A példa létrehoz egy új XML-fát, amelyben az egyes ügyfelek rendelései az elem egy Orders elemében Customer találhatók. Az eredeti dokumentum egy elemet is tartalmaz CustomerID az Order elemben; ezt az elemet nem adja meg az új fa.

XElement co = XElement.Load("CustomersOrders.xml");
XElement newCustOrd =
    new XElement("Root",
        from cust in co.Element("Customers").Elements("Customer")
        select new XElement("Customer",
            cust.Attributes(),
            cust.Elements(),
            new XElement("Orders",
                from ord in co.Element("Orders").Elements("Order")
                where (string)ord.Element("CustomerID") == (string)cust.Attribute("CustomerID")
                select new XElement("Order",
                    ord.Attributes(),
                    ord.Element("EmployeeID"),
                    ord.Element("OrderDate"),
                    ord.Element("RequiredDate"),
                    ord.Element("ShipInfo")
                )
            )
        )
    );
Console.WriteLine(newCustOrd);
Dim co As XElement = XElement.Load("CustomersOrders.xml")
Dim newCustOrd = _
   <Root>
       <%= From cust In co.<Customers>.<Customer> _
           Select _
           <Customer>
               <%= cust.Attributes() %>
               <%= cust.Elements() %>
               <Orders>
                   <%= From ord In co.<Orders>.<Order> _
                       Where ord.<CustomerID>.Value = cust.@CustomerID _
                       Select _
                       <Order>
                           <%= ord.Attributes() %>
                           <%= ord.<EmployeeID> %>
                           <%= ord.<OrderDate> %>
                           <%= ord.<RequiredDate> %>
                           <%= ord.<ShipInfo> %>
                       </Order> _
                   %>
               </Orders>
           </Customer> _
       %>
   </Root>
Console.WriteLine(newCustOrd)

Ez a példa a következő kimenetet hozza létre:

<Root>
  <Customer CustomerID="GREAL">
    <CompanyName>Great Lakes Food Market</CompanyName>
    <ContactName>Howard Snyder</ContactName>
    <ContactTitle>Marketing Manager</ContactTitle>
    <Phone>(503) 555-7555</Phone>
    <FullAddress>
      <Address>2732 Baker Blvd.</Address>
      <City>Eugene</City>
      <Region>OR</Region>
      <PostalCode>97403</PostalCode>
      <Country>USA</Country>
    </FullAddress>
    <Orders />
  </Customer>
  <Customer CustomerID="HUNGC">
    <CompanyName>Hungry Coyote Import Store</CompanyName>
    <ContactName>Yoshi Latimer</ContactName>
    <ContactTitle>Sales Representative</ContactTitle>
    <Phone>(503) 555-6874</Phone>
    <Fax>(503) 555-2376</Fax>
    <FullAddress>
      <Address>City Center Plaza 516 Main St.</Address>
      <City>Elgin</City>
      <Region>OR</Region>
      <PostalCode>97827</PostalCode>
      <Country>USA</Country>
    </FullAddress>
    <Orders />
  </Customer>
  ...
</Root>

Példa: Olyan dokumentum létrehozása, amelynek alakja eltér a forrásdokumentumétól

Ez a példa átnevez néhány elemet, és egyes attribútumokat elemekké alakít át. ConvertAddressMeghívja az objektumlistát, amely visszaadja az XElement objektumok listáját. A metódus argumentuma egy olyan lekérdezés, amely meghatározza azt az Address összetett elemet, amelyben az Type attribútum értéke "Shipping". A példa AZ XML-dokumentum minta XML-fájlját használja: Tipikus vásárlási sorrend.

static IEnumerable<XElement> ConvertAddress(XElement add)
{
    List<XElement> fragment = new List<XElement>() {
        new XElement("NAME", (string)add.Element("Name")),
        new XElement("STREET", (string)add.Element("Street")),
        new XElement("CITY", (string)add.Element("City")),
        new XElement("ST", (string)add.Element("State")),
        new XElement("POSTALCODE", (string)add.Element("Zip")),
        new XElement("COUNTRY", (string)add.Element("Country"))
    };
    return fragment;
}

static void Main(string[] args)
{
    XElement po = XElement.Load("PurchaseOrder.xml");
    XElement newPo = new XElement("PO",
        new XElement("ID", (string)po.Attribute("PurchaseOrderNumber")),
        new XElement("DATE", (DateTime)po.Attribute("OrderDate")),
        ConvertAddress(
            (from el in po.Elements("Address")
            where (string)el.Attribute("Type") == "Shipping"
            select el)
            .First()
        )
    );
    Console.WriteLine(newPo);
}
Function ConvertAddress(ByVal add As XElement) As IEnumerable(Of XElement)
    Dim fragment = New List(Of XElement)
    fragment.Add(<NAME><%= add.<Name>.Value %></NAME>)
    fragment.Add(<STREET><%= add.<Street>.Value %></STREET>)
    fragment.Add(<CITY><%= add.<City>.Value %></CITY>)
    fragment.Add(<ST><%= add.<State>.Value %></ST>)
    fragment.Add(<POSTALCODE><%= add.<Zip>.Value %></POSTALCODE>)
    fragment.Add(<COUNTRY><%= add.<Country>.Value %></COUNTRY>)
    Return fragment
End Function

Sub Main()
    Dim po As XElement = XElement.Load("PurchaseOrder.xml")
    Dim newPo As XElement = _
        <PO>
            <ID><%= po.@PurchaseOrderNumber %></ID>
            <DATE><%= CDate(po.@OrderDate) %></DATE>
            <%= _
                ConvertAddress( _
                (From el In po.<Address> _
                Where el.@Type = "Shipping" _
                Select el) _
                .First() _
                ) _
            %>
        </PO>
    Console.WriteLine(newPo)
End Sub

Ez a példa a következő kimenetet hozza létre:

<PO>
  <ID>99503</ID>
  <DATE>1999-10-20T00:00:00</DATE>
  <NAME>Ellen Adams</NAME>
  <STREET>123 Maple Street</STREET>
  <CITY>Mill Valley</CITY>
  <ST>CA</ST>
  <POSTALCODE>10999</POSTALCODE>
  <COUNTRY>USA</COUNTRY>
</PO>

Lásd még