2010-12-14 5 views
0

Ceci me rend fou de chauve-souris! fichier de données client:Linq pour joindre des tables sur XElement.Name = XAttribute ("n")

<rows> 
    <row> 
     <CustomerID>ABC123</CustomerID> 
     <PrdcrCd>10</PrdcrCd> 
     <StrAdr>123 Main St., NW</StrAdr> 
     <City>Anytown</City> 
     etc. 
    </row> 
<rows> 

fichier de la carte pour transformer les données client en entrée acceptable:

<SourceEntries> 
    <map> 
     <Field n='CustomerID' m='201' /> 
     <Field n='StrAdr' m='315' /> 
     <Field n='City' m='316' /> 
     <Field n='PrdrCd' m='442' /> 
     etc. 
    </map> 
</SourceEntries> 

Enfin, le modèle pour l'entrée acceptable:

<template> 
    <Field n='ClientId' id='201' /> 
    <Field n='Street Address' id='315' /> 
    <Field n='City' id='316' /> 
    <Field n='ProducerCode' id='442' /> 
    etc. 
</template> 

Ainsi, à partir du fichier client Nom XElement, correspond à la valeur de l'attribut Source Entries 'n' et obtient la référence de la carte Entires source m. Ensuite, utilisez m pour faire correspondre un attribut d'élément de gabarit i, récupérez l'attribut de nom de gabarit 'n' et créez une nouvelle arborescence XElement en utilisant ce nom.

Depuis que je suis un noob chez Linq, et pas particulièrement expert en XML, je pensais que je commencerais lentement. Comme ceci:

var results = from t1 in clientXm.Elements("row").Descendants() 
     join t2 in sourceEntries.Elements("Field") on t1.Name equals t2.Attributes("n") into xRef 
     select new 
      { 
       (string)xRef.Attributes("n"), 
       (string)xRef.Attributes("m") 
      }; 

erreur d'abord, dans la jointure clause « sur t1.Name.LocalName est égal à » est ce type d'argument « string » est pas cessibles au paramètre type « TKey ». Ensuite, dans la clause select, pour les deux éléments qui m'intéressent, j'obtiens que "l'initialisation de projection de type anonyme doit être un nom simple ou une expression d'accès de membre". Oh, et bien sûr, les structures de fichiers XML sont des spécifications, donc je ne peux en changer aucune. À ce stade, je suis tellement confus Je ne sais pas si le monde est à l'envers, ou je suis debout sur ma tête. Puis-je acheter une idée ... ou au moins une voyelle? Tout le monde aide grandement apprécié.

EDIT

En utilisant LINQPad, j'ai essayé cette déclaration:

XElement _clientXml = XElement.Load(@"client.xml"); 
XElement _sourceEntries = XElement.Load(@"Client_Map.xml"); 

foreach (XElement clientData in _clientXml.Descendants("row").Descendants()){ 
    IEnumerable<XElement> mapRefs = 
     from mapData in _sourceEntries.Descendants("Field") 
     where clientData.Name.LocalName == (string) mapData.Attribute("n") 
     select mapData; 
    foreach (XElement item in mapRefs){ 
     Console.WriteLine(item.Attribute("m")); 
    } 
} 

Dans LINQPad, ce produit une liste de valeurs "m" - juste ce que je suis en train de faire à ce un pas de bébé. MAIS le même code exact dans VS ne me donne rien. Quand je débogue, mapRefs est un ensemble vide quand j'arrive au second foreach.

Cela a-t-il un sens?

Merci Randy

+0

Désolé, ne réalisais pas à quel niveau beaucoup ma frustration montrait à travers. .. S'il vous plaît pardonner. – EoRaptor013

Répondre

1

Certaines de vos entrées ne sont pas alignées correctement. Voici un bon départ lieu:

var rowText = 
@"<rows> 
    <row> 
     <CustomerID>ABC123</CustomerID> 
     <PrdrCd>10</PrdrCd> 
     <StrAdr>123 Main St., NW</StrAdr> 
     <City>Anytown</City> 
     etc. 
    </row> 
</rows>"; 
var sourceEntriesText = 
@"<SourceEntries> 
    <map> 
     <Field n='CustomerID' m='201' /> 
     <Field n='StrAdr' m='315' /> 
     <Field n='City' m='316' /> 
     <Field n='PrdrCd' m='442' /> 
     etc. 
    </map> 
</SourceEntries>"; 
var templateText = 
@"<template> 
    <Field n='ClientId' id='201' /> 
    <Field n='Street Address' id='315' /> 
    <Field n='City' id='316' /> 
    <Field n='ProducerCode' id='442' /> 
    etc. 
</template>"; 
var clientXm = XDocument.Parse(rowText); 
var sourceEntries = XDocument.Parse(sourceEntriesText); 
var results = from r in clientXm.Descendants("row") 
      from t1 in r.Elements() 
      let xRef = sourceEntries.Descendants("Field").FirstOrDefault(
         t2 => t1.Name == t2.Attribute("n").Value) 
      select new 
       { 
        t1, 
        xRef 
       }; 

Un peu plus des rendements de travail quelque chose probablement plus proche de ce que vous cherchez:

var results = from r in clientXm.Descendants("row") 
      from t1 in r.Elements() 
      join t2 in sourceEntries.Descendants("Field") 
      on t1.Name equals t2.Attribute("n").Value 
      join t3 in template.Descendants("Field") 
      on t2.Attribute("m").Value equals t3.Attribute("id").Value 
      select new 
       { 
        Name = t3.Attribute("n").Value, 
        Value = t1.Value, 
       }; 
+0

Cela semble fonctionner; en particulier le deuxième exemple. Malheureusement, je n'obtiens aucun résultat. Je vais devoir commencer par de petits pas et voir jusqu'où je vais. Merci, cependant, pour l'aide. – EoRaptor013

+0

@ EoRaptor013: J'ai utilisé le code donné dans LINQPad, et il a produit des résultats. Vous voudrez peut-être vérifier vos entrées XML. Votre mappage de code de producteur, par exemple, ne correspond pas. Il y avait aussi quelques autres problèmes. – StriplingWarrior

+0

Pas de joie. Là où cela semble exploser est que je ne peux pas obtenir une correspondance entre les données du client XElement.XName.LocalName et le nom de la carte (chaîne) XElement.XAttribute ("n"). Même si les deux chaînes correspondent effectivement - en les regardant dans les fichiers sources, la jointure ne peut pas le récupérer. Existe-t-il un moyen de déboguer ces instructions afin que je puisse voir quel attribut n renvoie? Merci. – EoRaptor013

0

Eh bien, il est facile de corriger les erreurs du compilateur:

var results = from t1 in clientXm.Elements("row").Descendants() 
       join t2 in sourceEntries.Elements("Field") 
       on t1.Name.LocalName equals (string) t2.Attribute("n") into xRef 
       select new 
       { 
        N = (string)xRef.Attributes("n"), 
        M = (string)xRef.Attributes("m") 
       }; 

Cependant, je ne sais pas comment vous avez l'intention la distribution IEnumerable<XAttribute>-string à travailler dans la projection

Je suppose que vous ne voulez pas voulez une jointure de groupe (ce qui est ce que vous obtenez avec join ... dans. Mais je ne comprends pas comment fonctionne votre exemple de données, donc c'est difficile de vous donner le bon code. D'où devrait provenir ClientId, par exemple? Vous avez seulement dans votre échantillon sortie ... en supposant que est votre sortie d'échantillon, bien sûr. Fondamentalement, si vous pouviez simplifier vos données d'échantillon en deux entrées et une sortie, et expliquer comment la sortie est dérivée, cela rendrait la vie plus facile ... pour le moment, ce n'est pas clair.

+0

CustomerID dans le fichier client correspond à l'attribut SourceEntries n = 'CustomerID'. Attribut SourceEntries m = '201' puis pointant vers l'attribut de modèle id = '201'. L'attribut template n = 'ClientId' me donne le nouveau nom de l'élément. – EoRaptor013

+0

Jusqu'ici, tout ce que j'essaie de faire ici est simplement de récupérer les attributs 'n' et 'm' appropriés dans le fichier Source Entries. L'étape suivante consisterait à joindre le fichier Template sur sourceEntries.m = template.id. Je créerais alors une nouvelle arborescence XML en utilisant l'attribut template n value comme nom d'élément. S'il y a une meilleure façon de procéder, compte tenu des contraintes dans les trois dossiers, je serais extrêmement reconnaissant de l'entendre. – EoRaptor013