# Simplify an XMLObject by keeping only specific elements

I would like to extract from an XMLObject only the XMLElements with a specific tag.

Inspired from the Mathematica help (section transforming XML, introduction, the example with the colours), I have tried this code :

Definition of the XMLObject:

XMLtest =
XMLObject[
XMLElement["YO", {},
{XMLElement["YO", {}, 2],
XMLElement["BA", {},
{XMLElement["YO", {},
{XMLElement["BA", {}, 2]}], XMLElement["BA", {}, 2]}]}]]


Code so as to suppress all the elements different from "YO" in order to keep only the elements with the tag "YO":

XMLtest2 = XMLtest /. XMLElement[Except["YO"], _, _] -> Sequence[]


The above code works well.

Code so as to suppress the XMLElements without the tag "BA":

XMLtest2 = XMLtest /. XMLElement[Except"BA", _, _] -> Sequence[]


For this latter code, I have a problem with the answer because I obtain only the XMLObject. However, I would like to obtain a tree of XMLElements under the XMLObject.

• Somehow you ended up with the \[RightArrow] character when instead you need either plain text -> or \[Rule]. Correct this and your replacement will work. I am closing this question as a "simple syntax error" now. If you find that I am mistaken or have other problem please comment here, starting your comment with @Mr.Wizard so that I will be notified. – Mr.Wizard May 17 '15 at 13:35
• Sometimes I like this way of defining a behavior for an XML element: xmltest2 = Block[{XMLElement}, XMLElement["BA", __] := Sequence[]; XMLtest] and xmltest3 = Block[{XMLElement}, XMLElement[Except["YO"], __] := Sequence[]; XMLtest]. – Michael E2 May 17 '15 at 13:44
• @MichaelE2 That seems harder than using DeleteCases; do you find otherwise? – Mr.Wizard May 17 '15 at 14:37
• @Mr.Wizard For any given narrow task, there is probably a simpler solution than the one I proposed. But when I use XML data, which is not often so take this with a grain of salt, I often want to do several things that are functions of the tag, attributes, and data. I find it easier to think about such a problem in terms of XMLElement as a function. OTOH, there is a difference I overlooked at first. The OP's code would do one replacement, mine three, due to ReplaceAll vs. evaluation. So maybe my comment isn't so helpful here. – Michael E2 May 17 '15 at 14:55
• @MichaelE2 I made some corrections. Thanks a lot for your very constructive help. – Bendesarts May 17 '15 at 21:47

I'm still not sure what you want. I think it is this, but it does not reproduce the tree you have in the question for the Except["YO"] case.

contractElement[xml_, tagpat_] := Block[{XMLElement},
XMLElement[tagpat, _, data_] /; FreeQ[data, XMLElement] := Sequence[];
XMLElement[tagpat, _, data_] := Sequence @@ data;
xml
];

contractElement[XMLtest, Except["YO"]] // TreeForm
contractElement[XMLtest, Except["BA"]] // TreeForm


Side note: I thought the syntax for XMLObject is XMLObject[type][data], which does not quite conform with you example. For instance, this might produce an error, if a root is required:

XMLtest2 =
XMLObject[
XMLElement["YO", {},
{XMLElement["BA", {}, 2],
XMLElement["BA", {},
{XMLElement["YO", {}, 2],
XMLElement["BA", {}, 2]}]}]];
XMLtest2 // TreeForm
contractElement[XMLtest2, Except["BA"]] // TreeForm


• Thank a lot for your help. Your code perfectly answers to my need. However, I would prefer a code with an approach as in this post : mathematica.stackexchange.com/questions/83622/… That is to say a way which easily permit to add more conditions on the attributes of an XMLElements. Thank you for your help. – Bendesarts May 18 '15 at 21:05
• You can define XMLElement[tag_, attr_, data_] := ... however you want. Such as XMLElement[tag_, attr_, data_] := XMLElement[tag, Join[attr, myattributes], data], if you wish to add a list myattributes to the list of attribute attr`. – Michael E2 May 18 '15 at 21:49
• @Bendesarts please, take a tour. – Kuba May 19 '15 at 5:57