开发者

xml node hierarchy transform

开发者 https://www.devze.com 2023-02-13 06:42 出处:网络
I\'m wondering if there is a way to flip the hierarchy of node using linq to XML or xslt. I\'m want to transform

I'm wondering if there is a way to flip the hierarchy of node using linq to XML or xslt.

I'm want to transform

<hardware>
    <software/>
    <software/>
</hardware>
<hardware>
    <software/>
    <software/>
</hardware>

Where I use the existing parent - child relationship and just flip and rebuild the stru开发者_StackOverflow中文版cture to look like this.

<software>
    <hardware/>
    <hardware/>
</software>
<software>
    <hardware/>
    <hardware/>
</software>


I'm wondering if there is a way to flip the hierarchy of node using linq to XML or xslt.

. . . . . . .

Where I use the existing parent - child relationship and just flip and rebuild the structure.

Yes. This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kSoftByName" match="software"
  use="@name"/>

 <xsl:template match=
  "software[generate-id()
           =
            generate-id(key('kSoftByName',@name)[1])
           ]
  ">
  <xsl:copy>
   <xsl:copy-of select="@*"/>
   <xsl:apply-templates mode="copy"
      select="key('kSoftByName',@name)/.."/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="hardware" mode="copy">
  <xsl:copy>
   <xsl:copy-of select="@*"/>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

when applied on this XML document:

<inventory>
    <hardware name="PC">
        <software name="Office"/>
        <software name="Safari"/>
        <software name="Windows"/>
    </hardware>
    <hardware name="Mac">
        <software name="Safari"/>
        <software name="Office"/>
        <software name="Leopard"/>
    </hardware>
</inventory>

produces the wanted, correct result:

<software name="Office">
   <hardware name="PC"/>
   <hardware name="Mac"/>
</software>
<software name="Safari">
   <hardware name="PC"/>
   <hardware name="Mac"/>
</software>
<software name="Windows">
   <hardware name="PC"/>
</software>
<software name="Leopard">
   <hardware name="Mac"/>
</software>

Explanation: Muenchian method for grouping.


Here's the LINQ version.

Given xml like this:

var xml = @"
<inventory>
    <hardware name=""PC"">
        <software name=""Office""/>
        <software name=""Safari""/>
        <software name=""Windows""/>
    </hardware>
    <hardware name=""Mac"">
        <software name=""Safari""/>
        <software name=""Office""/>
        <software name=""Leopard""/>
    </hardware>
</inventory>";

Here's the query to pull it apart:

var xd = XDocument.Parse(xml);

var query =
    from h in xd.Root.Elements()
    from s in h.Elements()
    select new
    {
        hardware = h.Attribute("name").Value,
        software = s.Attribute("name").Value
    };

var lookup = query.ToLookup(q => q.software, q => q.hardware);

And here's the query to put it back together again, flipped as desired:

var result =
    new XDocument
    (
        new XElement
        (
            "inventory",
            from s in query.Select(q => q.software).Distinct()
            select new XElement
            (
                "software",
                new XAttribute("name", s),
                from h in lookup[s].Distinct()
                select new XElement
                (
                    "hardware",
                    new XAttribute("name", h)
                )
            )
        )
    );

/*
<inventory>
  <software name="Office">
    <hardware name="PC" />
    <hardware name="Mac" />
  </software>
  <software name="Safari">
    <hardware name="PC" />
    <hardware name="Mac" />
  </software>
  <software name="Windows">
    <hardware name="PC" />
  </software>
  <software name="Leopard">
    <hardware name="Mac" />
  </software>
</inventory> 
*/
0

精彩评论

暂无评论...
验证码 换一张
取 消