I XML filen nedan finns Word.Bookmark.Start Jag gjorde liknande sak för ett tag sedan då jag hade ett program (yafray) som hade filformat som var XML och jag behövde göra varianter (några hundra åt gången) av en i förväg genererad XML-fil fast med vissa värden utbytta. Exemplet ovan var i.o.f.s. kort (med endast ett bokmärke) och när det gäller aktuella XML-scheman så verkar det som om man måste ladda ner och installera "Office 2003: XML Reference Schemas" för att kunna få se dem... och det orkar jag inte, så jag gissar hur strukturen ska se ut m.h.a. exemplet ovan. Tackar Tomas I så fall är det antaligen enklast att istället selektera de annotation-element där ett bokmärke börjar: Tror jag är lite fel ute för det blev inte riktigt rätt. Ändrade så jag går mot annotation-elementen.Iterera igenom XMLDocument
Det jag vill är att man ska kunna loopa igenom XMLDocumentet och hitta alla bokmärkena och sen
ändra texten som står i det bokmärket. I detta fallet står det "TEXTEN" och bokmärket heter MyBOOKMARK.
Kan någon hjälpa mig hur jag ska iterera igenom mitt XMLDocument för att hitta dessa.
Har försökt men hittar inte det.
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<?mso-application progid="Word.Document"?>
- <w:wordDocument xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:sl="http://schemas.microsoft.com/schemaLibrary/2003/core" xmlns:aml="http://schemas.microsoft.com/aml/2001/core" xmlns:wx="http://schemas.microsoft.com/office/word/2003/auxHint" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" w:macrosPresent="no" w:embeddedObjPresent="no" w:ocxPresent="no" xml:space="preserve">
+ <o:DocumentProperties>
+ <w:fonts>
+ <w:styles>
+ <w:docPr>
- <w:body>
- <wx:sect>
<aml:annotation aml:id="0" w:type="Word.Bookmark.Start" w:name="MyBOOKMARK" />
- <w:p>
- <w:r>
<w:t>TEXTEN</w:t>
</w:r>
<aml:annotation aml:id="0" w:type="Word.Bookmark.End" />
</w:p>
- <w:sectPr>
<w:pgSz w:w="11906" w:h="16838" />
<w:pgMar w:top="1417" w:right="1417" w:bottom="1417" w:left="1417" w:header="708" w:footer="708" w:gutter="0" />
<w:cols w:space="708" />
<w:docGrid w:line-pitch="360" />
</w:sectPr>
</wx:sect>
</w:body>
</w:wordDocument>Sv: Iterera igenom XMLDocument
Jag gjorde då ett litet program i C# som använde XPath för att hitta de noder som jag sedan skulle ändra värden i. Att skriva XPath-queries kan dock vara något knivigt, men jag använde Visual XPath (se http://weblogs.asp.net/nleghari/articles/visualxpath.aspx ) för att bygga upp XPath-uttrycken (Visual XPath kan även generera viss skelett-kod i C# har jag för mig).
Förmodligen går detta även att lösa med xslt, men det har jag inte gjort (i det fallet som jag gjorde så läste jag de nya värdena från en databas, så C#-lösningen var enklast).
Som kommentar kan jag sedan säga att det du gör är ännu enklare om du gör det med ett macro i Word (men det kanske inte är tillgängligt där du kör programmet?). Att ersätta kod i bokmärken är busenkelt i ett macro i MS Word.
/AndreasSv: Iterera igenom XMLDocument
Om den generella strukturen är att ett bokmärke alltid ska definieras av ett annotation-element efterföljd med en /p/r/t -struktur, så tror jag att följande XPath-uttryck ska fungera för att erhålla en nodlista med w:t-elementen
//aml:annotation[@w:type='Word.Bookmark.Start']/following-sibling::w:p/w:r/w:t
C#-kod för att ändra innehållet i "w:t -elementen":
XmlDocument oXmlDocument = new XmlDocument();
oXmlDocument.Load(filnamn);
XmlNamespaceManager nm = new XmlNamespaceManager(oXmlDocument.NameTable);
nm.AddNamespace("w", "http://schemas.microsoft.com/office/word/2003/wordml");
nm.AddNamespace("aml", "http://schemas.microsoft.com/aml/2001/core");
XmlNodeList oXmlNodeList = oXmlDocument.SelectNodes("//aml:annotation[@w:type='Word.Bookmark.Start']/following-sibling::w:p/w:r/w:t", nm);
for(int i=0; i<oXmlNodeList.Count; i++)
{
oXmlNodeList[i].InnerText = "det nya värdet på w:t-elementet";
}
oXmlDocument.Save(nyttfilnamn);
/ TomasSv:Iterera igenom XMLDocument
Men hur kollar jag vad mitt bokmärke heter för jag ska ju ersätta texten olika beroende på vad bokmärket heter.Sv: Iterera igenom XMLDocument
//aml:annotation[@w:type='Word.Bookmark.Start']
och sedan kan du plocka ut värdet på attributet "w:name" och lagra den i en variabel, och sedan gå framåt (med vanlig C#-kod) tills du hamnar i "w:p" och sedan gå ner i den tills du får en referens till "w:t" så att du kan ändra värdet till det som du sparade i variabeln.
Den XmlNodeList som returneras av SelectNodes-metoden innehåller XmlNode-element, och den klassen finns dokumenterad här:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemxmlxmlnodememberstopic.asp
och där finns properties som kan användas för att navigera framåt och neråt bland xml-elementen.
/ TomasSv:Iterera igenom XMLDocument
Men tror jag gör stegar igenom den fel sen. Värdet ersätts visserligen nu, men när jag ska öppna den i word så finns inget där.
<Code>
XmlDocument oXmlDocument = new XmlDocument();
oXmlDocument.Load(filePath);
XmlNamespaceManager nm = new XmlNamespaceManager(oXmlDocument.NameTable);
nm.AddNamespace("w", "http://schemas.microsoft.com/office/word/2003/wordml");
nm.AddNamespace("aml", "http://schemas.microsoft.com/aml/2001/core");
XmlNodeList oXmlNodeList = oXmlDocument.SelectNodes("//aml:annotation[@w:type='Word.Bookmark.Start']", nm);
for (int i = 0; i < oXmlNodeList.Count; i++)
{
foreach (XmlAttribute xa in oXmlNodeList[i].Attributes)
{
string BookmarkName ="";
if (xa.Name == "w:name")
{
BookmarkName = xa.InnerText;
if(BookmarkName == "MyBookmark")
{
if (oXmlNodeList[i].NextSibling.Name == "w:p")
oXmlNodeList[i].NextSibling.InnerText = "nytt värde";
}
if(BookmarkName == "MyBookmark2")
{
if (oXmlNodeList[i].NextSibling.Name == "w:p")
oXmlNodeList[i].NextSibling.InnerText = "nytt värde2";
}
}
}
}
</code>