Pregunta

Tengo dos documentos: uno es un formato de archivo XML personalizado, el otro es un feed RSS con un montón de extensiones personalizadas. Quiero completar los campos en el archivo XML con los valores encontrados en la fuente RSS cuando un valor de elemento coincide.

Esto es para un proceso fuera de línea que se ejecutará varias veces manualmente: no necesita funcionar bien, ser tan tolerante a fallas, etc. El trabajo manual o la intervención están bien.

Mi documento XML maestro se ve así:

    <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>

La fuente RSS es RSS estándar con algún campo adicional:

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

Me gustaría extraer los campos adicionales del documento RSS al documento XML cuando el valor coincida con el valor:

    <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>

Me gustaría usar c #, LINQ o algún tipo de Excel-fu. Supongo que si tuviera que hacerlo, podría lidiar con XSLT siempre que no implique que yo mismo escriba mucho XSLT.

Miré esta pregunta, pero no me pareció tan útil para lo que estoy tratando de hacer: Combinar documentos XML

¿Fue útil?

Solución

¡Suena como un trabajo para 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);

La solución anterior supone que el documento RSS se parece a esto:

<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>

Otros consejos

Agregue esto a una transformación de identidad XSLT (también deberá agregar la declaración de espacio de nombres para el espacio de nombres http://test.com al elemento de nivel superior de la transformación):

<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 ya ha leído el RSS en un XmlDocument en su programa, puede pasarlo al XSLT como parámetro en lugar de utilizar la función document () para leerlo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top