Reputation: 627
I'm new to XML and C# so I'm having a little trouble implementing the following. Hopefully someone can point me in the right direction. So I'm developing in C# with OpenXML 2.5 and I'm trying to check, after I create a Font, if that Font already exists in the Font collection. If it already does then I want to return the index of the Font.
I am stuck on writing an efficient method to compare these Font objects and I believe that comparing their respective XML code is the way to go. I believe that these Font objects are wrappers for XML code. So I thought that I should be able to compare two XML elements and figure out if the Font already exists or not.
Does this make any sense? Here is an example, because I fear that I'm being overly complicated in my explanation.
1. Basically, I want to find if this:
<x:font>
<x:b />
<x:sz val="18" />
<x:color theme="3" />
<x:name val="Cambria" />
<x:family val="2" />
<x:scheme val="major" />
</x:font>
2. Already exists in here:
<x:fonts count="18" x14ac:knownFonts="1" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<x:font>
<x:sz val="11" />
<x:color theme="1" />
<x:name val="Calibri" />
<x:family val="2" />
<x:scheme val="minor" />
</x:font>
<x:font>
<x:sz val="11" />
<x:color theme="1" />
<x:name val="Calibri" />
<x:family val="2" />
<x:scheme val="minor" />
</x:font>
<x:font>
<x:b />
<x:sz val="18" />
<x:color theme="3" />
<x:name val="Cambria" />
<x:family val="2" />
<x:scheme val="major" />
</x:font>
<x:font>
<x:b />
<x:sz val="15" />
<x:color theme="3" />
<x:name val="Calibri" />
<x:family val="2" />
<x:scheme val="minor" />
</x:font>
</x:fonts>
3. And the method returns the index of the Font. So in this example my function would return 2
.
Any help with this would be greatly appreciated!
thanks, Justin
Upvotes: 1
Views: 768
Reputation: 1
In OpenXML v3 a more efficient way was introduced: OpenXmlElementComparers
It will allow you to just to OpenXmlElementComparers.Default.Equals(a,b)
.
It is also possible to have more granular control over how equality is defined by creating using OpenXmlElementEqualityOptions
The OuterXml property used to be the easiest way to solve this problem. However the performance wasn't very good due to high amounts of allocations as described here.
Upvotes: 0
Reputation: 627
Appreciate the help, but figured out an easier way of doing it actually from within the sdk. Turns out there is a method called OuterXml
for each OpenXml Object.
According to the Microsoft definition: OuterXml: Gets the markup that represents the current element and all of its child elements.
It is much better than InnerXml: Gets or sets the markup that represents only the child elements of the current element.
So I can simply do:
private Stylesheet _stylesheet = _workbookPart.WorkbookStylesPart.Stylesheet;
public int GetFontIndex(Font font)
{
int index = 0;
foreach (var existingFont in _stylesheet.Descendants<Font>())
{
if (font.OuterXml.Equals(existingFont.OuterXml)) return index;
index++;
}
return -1;
}
Upvotes: 1
Reputation: 7344
Check out XPath for querying XMLDocuments, and then you can use FindNode() on the XMLDocument with the XPath query.
However, what it won't do is return the Index Number. Unless otherwise directed, XML nodes are not ordered and so rthe idea of saying "it's the third" is not done because next time you look it might be the fifth! (Probably not, but behavior like that would be within the spec of XML). What you can do, though, is get the actual node () from which you can get the parent () node that contains it.
Upvotes: 1