0

I have a huge XML file. Looks somthing like the following

<component name='comp1'>
  <child> ... </child>
  <child> ... </child>
  <optional id='1'> ... </optional>
</component>

<component name='comp2'>
  <child> ... </child>
  <child> ... </child>
  <optional id='1'> ... </optional>  
  <optional id='1'> ... </optional>
  <optional id='2'> ... </optional>
</component>

I want to select optional elements based on their ids from each component without repeating any id within the same component.

Simply, I want the following output for comp2, for example:

Comp2
1
2

My problem is to select optional elements that has similar id one time only.

I am using Xpath with JET1 (java Emitter Template) I am iterating each component looking for optional elements and printing their text(). However, my loop is resulting in the following

 Comp2
    1
    1
    2

I want to eliminate duplicated results.

My JET temple:

<c:iterate select="//component/optional" var="Optional">
<c:get select="$Optional"/>
</c:iterate>
Kirill Polishchuk
  • 54,804
  • 11
  • 122
  • 125
607-GXF
  • 9
  • 3

2 Answers2

0

Try this XPath:

//component/optional[not(@id = following-sibling::optional/@id)]
Kirill Polishchuk
  • 54,804
  • 11
  • 122
  • 125
  • We don't know how big "huge" is (it could mean anything from 1Mb to 100Gb), but whatever it means, it means that a solution with O(n^2) performance is not a good idea. I'm afraid I can't offer a solution of my own because I don't know JET. – Michael Kay Apr 20 '15 at 08:10
  • "$currComp//optional/guard/booleanExp/equals/symbol This is the path to the last element I want to extract without duplication. It's a text element with no attributes. so How can I include it in your provided XPath? – 607-GXF Apr 20 '15 at 15:48
0

I don't know what JET supports, but believe that this XPath 2.0 expression may give you a good idea for a solution in your case:

/*/component[@name eq 'comp2']/optional
             [not(@id eq preceding-sibling::*[1][self::optional]/@id)]
                                                              /@id/string()

When this XPath 2.0 expression is evaluated having this current document:

<t>
    <component name='comp1'>
        <child> ... </child>
        <child> ... </child>
        <optional id='1'> ... </optional>
    </component>
    <component name='comp2'>
        <child> ... </child>
        <child> ... </child>
        <optional id='1'> ... </optional>
        <optional id='1'> ... </optional>
        <optional id='2'> ... </optional>
    </component>
</t>

the wanted result is produced:

1 2

The time complexity for evaluating this XPath expression is only linear ( O(N) ) and not quadratic ( O(N^2) )

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • Thanks. But JET uses Xpath 1. I'm not sure if this will work. Plus, What if the id attribute is a child element of optional? and not included as an attribute? I tired //component/optional/text() but nothing again! – 607-GXF Apr 22 '15 at 17:31
  • @607-GXF, You seem confused about what is the format of the source XML document -- you need to clarify this, before asking a question, or the question is less meaningful. As for XPath2 -- it is very easily translated to a few XPath 1.0 expressions (just replace `eq` with `=`, and also have getting the string value of the attributes in a second step)that you have to execute and link together in a meaningful way using your Jet language (which I don't know). This is why I said: "just to give you an idea" – Dimitre Novatchev Apr 22 '15 at 18:30