2009-07-30 7 views
2

J'ai deux documents - l'un est un format de fichier XML personnalisé, l'autre est un flux RSS avec un tas d'extensions personnalisées. Je veux remplir les champs dans le fichier XML avec les valeurs trouvées dans le flux RSS quand une valeur d'élément correspond.Fusion de documents XML en vrac

Ceci est pour un processus hors ligne qui sera exécuté manuellement plusieurs fois - il n'a pas besoin d'être performant, d'être tolérant aux pannes, etc. Le travail manuel ou l'intervention sont corrects.

Mon document XML maître ressemble à ceci:

<videos> 
     <video> 
      <title>First Video</title> 
      <code>AAA123</code> 
      <id>decaf-decaf-decaf-decaf</id> 
      <description>lots of text here...</description> 
     </video> 
     <video> 
      <title>Second Video with no code</title> 
      <code></code> 
      <id>badab-badab-badab-badab</id> 
      <description>lots of text here...</description> 
     </video> 
    </videos> 

Le flux RSS est standard RSS avec un champ supplémentaire:

<ns:code>AAA123</ns:code> 
    <ns:type>Awesome</ns:type> 
    <ns:group>Wonderful</ns:group> 

Je voudrais tirer les champs supplémentaires du document RSS dans le document XML lorsque l'espace de noms value matches the value:

 <videos> 
     <video> 
      <title>First Video</title> 
      <code>AAA123</code> 
      <id>decaf-decaf-decaf-decaf</id> 
      <description>lots of text here...</description> 
      <type>Awesome</type> 
      <group>Wonderful</group> 
     </video> 
     <video> 
      <title>Second Video with no code</title> 
      <code></code> 
      <id>badab-badab-badab-badab</id> 
      <description>lots of text here...</description> 
      <type></type> 
      <group></group> 
     </video> 
    </videos> 

I'd most like to use c#, LINQ, or some kind of Excel-fu. I guess if I had to I could deal with XSLT as long as it doesn't involve me writing much XSLT myself.

I looked at this question, but it didn't seem all that helpful for what I'm trying to do: Merge XML documents

Répondre

5

Sounds like a job for LINQ to XML!

var vidDoc = XDocument.Parse(vidXml); 
var rssDoc = XDocument.Parse(rssXml); 
var videos = vidDoc.XPathSelectElements("/videos/video"); 
var rssItems = rssDoc.XPathSelectElements("/rss/channel/item"); 
var matches = videos.Join(
    rssItems, 
    video => video.Element(XName.Get("code")).Value, 
    rssItem => rssItem.Element(XName.Get("code", "http://test.com")).Value, 
    (video, item) => new {video, item}); 

foreach (var match in matches) 
{ 
    var children = match.item.Elements() 
     .Where(child => child.Name.NamespaceName == "http://test.com" && 
         child.Name.LocalName != "code"); 

    foreach (var child in children) 
    { 
     //remove the namespace 
     child.Name = XName.Get(child.Name.LocalName); 
     match.video.Add(child); 
    } 
} 

vidDoc.Save(Console.Out); 

The above solution assumes that the RSS document looks something like this:

<rss xmlns:ns="http://test.com" version="2.0"> 
    <channel> 
    <item> 
     <title>AAA123</title> 
     <link>http://test.com/AAA123</link> 
     <pubDate>Sun, 26 Jul 2009 23:59:59 -0800</pubDate> 
     <ns:code>AAA123</ns:code> 
     <ns:type>Awesome</ns:type> 
     <ns:group>Wonderful</ns:group> 
    </item> 
    </channel> 
</rss> 
+0

Cela a l'air génial! Je vais tester demain matin et marquer comme réponse alors. –

1

Add this to an XSLT identity transform (you'll also need to add the namespace declaration for the http://test.com à l'élément de niveau supérieur de la transformation):

<xsl:variable name="rss" select="document('rss.xml')"/> 

<xsl:template match="video"> 
    <xsl:apply-templates select="@* | node()"/> 
    <xsl:apply-templates select="$rss/rss/channel/item[ns:code=current()/code]"/> 
</xsl:template> 

<!-- this keeps the code element from getting copied --> 
<xsl:template match="ns:code"/> 

<!-- this will copy all of the content of the ns:* elements, not just their text --> 
<xsl:template match="ns:*"> 
    <xsl:element name="{local-name()}"> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:element> 
</xsl:template> 

Si vous avez déjà lu le RSS dans un XmlDocument dans votre programme, vous pouvez le passer dans le paramètre XSLT en tant que paramètre au lieu d'utiliser la fonction document() pour le lire.

+0

Merci, cela semble bon. Je vais rester dans l'approche C# car je suis plus à l'aise avec ça et c'est plus facile (pour moi) de déboguer. –