List all elements in xml with full paths

Discussion in 'XML' started by fazl.rahman@volcanomail.com, Jun 20, 2008.

  1. Guest

    Hi

    I've not been able to find nor concoct a simple filter to convert an
    xml file into a list of all its elements (with full paths). This
    seems to be a simple requirement...!

    As an example I would like this input ...:

    <?xml version="1.0"?>
    <Person>
    <FirstName>Elvis</FirstName>
    <LastName>Presley</LastName>
    </Person>

    ....To result in this output :

    /Person
    /Person/FirstName
    /Person/LastName

    Any gurus care to share a concise xsl that does this ?

    I happened across the 'navigation shell' feature of xmllint during my
    fumbling attempts recently - so, lacking a suitbale xslt script, I
    guess I could resort to post-processing the output of the shell's "du"
    command, which looks like this:

    $ xmllint --shell Person.xml
    / > du
    /
    Person
    FirstName
    LastName

    (If the navigating shell from xmllint incorporated a unix-like 'find'
    command, sheesh.. that would be so cool.)

    Appreciate (any friendly :) feedback..
    Thanks, Fazl
    , Jun 20, 2008
    #1
    1. Advertising

  2. wrote:

    > I've not been able to find nor concoct a simple filter to convert an
    > xml file into a list of all its elements (with full paths). This
    > seems to be a simple requirement...!
    >
    > As an example I would like this input ...:
    >
    > <?xml version="1.0"?>
    > <Person>
    > <FirstName>Elvis</FirstName>
    > <LastName>Presley</LastName>
    > </Person>
    >
    > ...To result in this output :
    >
    > /Person
    > /Person/FirstName
    > /Person/LastName
    >
    > Any gurus care to share a concise xsl that does this ?


    Well what do you want to generate if there are namespaces used? What do
    you want to generate if there are several FirstName and/or LastName
    child elements?

    --

    Martin Honnen
    http://JavaScript.FAQTs.com/
    Martin Honnen, Jun 20, 2008
    #2
    1. Advertising

  3. wrote:

    > I've not been able to find nor concoct a simple filter to convert an
    > xml file into a list of all its elements (with full paths). This
    > seems to be a simple requirement...!
    >
    > As an example I would like this input ...:
    >
    > <?xml version="1.0"?>
    > <Person>
    > <FirstName>Elvis</FirstName>
    > <LastName>Presley</LastName>
    > </Person>
    >
    > ...To result in this output :
    >
    > /Person
    > /Person/FirstName
    > /Person/LastName
    >


    You might consider using XMLgawk:

    $ xgawk -lxml 'XMLSTARTELEM {print XMLPATH}' persons.xml
    /Person
    /Person/FirstName
    /Person/LastName
    Jürgen Kahrs, Jun 20, 2008
    #3
  4. Correctly indented, it should look like this:

    $ xgawk -lxml 'XMLSTARTELEM {print XMLPATH}' persons.xml
    /Person
    /Person/FirstName
    /Person/LastName
    Jürgen Kahrs, Jun 20, 2008
    #4
  5. Guest

    On 20 Jun., 18:16, Martin Honnen <> wrote:
    > Well what do you want to generate if there are namespaces used? What do
    > you want to generate if there are several FirstName and/or LastName
    > child elements?


    I think I'd like to see this kind of output (if these elements are in
    a namespace Foo)

    Eg:

    /
    /Foo:person
    /Foo:person/FirstName
    /Foo:person/LastName

    If there are several child elements, I want to see them all listed in
    document order.

    -Fazl
    , Jun 21, 2008
    #5
  6. Guest

    On 20 Jun., 18:15, "szomiz" <>
    wrote:
    > <xsl:for-each select="ancestor-or-self::*">
    >     <xsl:value-of select="concat('/',name())"/>
    >     <!--xsl:value-of
    > select="concat('[',count(preceding-sibling::*[name()=name(current())])+1,']­')"/-->
    >
    > sz.


    I tried wrapping this suggestion in an <xsl:transform> tag and invoked
    it thus:

    $ xsltproc.exe pathify.xsl Person.xml

    Well, a blank line comes out.

    :-(

    Then I noticed that your for-each tag is missing it's closing tag.

    Adding that, and adding a <xsl:template> container too also gives no
    output.

    Is this the kind of xslt script you mean by your code snippet ?

    <?xml version="1.0"?>
    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:eek:utput method="text"/>
    <xsl:template match="*">

    <xsl:for-each select="ancestor-or-self::*">
    <xsl:value-of select="concat('/',name())"/>
    </xsl:for-each>

    </xsl:template>
    </xsl:transform>


    (If you tested it, can you share the actual script with us ?)

    What am I doing wrong ?

    Fazl
    , Jun 21, 2008
    #6
  7. Guest

    On 21 Jun., 03:15, wrote:
    > On 20 Jun., 18:15, "szomiz" <>

    [...]
    > Then I noticed that your for-each tag is missing it's closing tag.

    [...]
    > What am I doing wrong ?


    After a little tinkering (xsltproc's -v switch is useful), the
    transform below delivers what i wanted. (BTW I expect to find this
    useful to quickly check whether an element with a given name appears
    in a large xml file and if so, at what level of nesting.)

    I had to put your code in an xsl:template matching "node()" and
    calling itself on the current node's contents after performing it's
    ancestral rites. Note the xsl:text element I added to force a new
    line for each new element output - Is there a cleaner way to do
    this ?

    I don't like having to break the indentation of the script, but if I
    line up the end tag with the start tag it indents the output by the
    same amount of space.

    Thanks, Fazl

    PS Here's how it looks now:

    fazl@ubuntu:~/bin/xslt$ cat Person.xml
    <?xml version="1.0"?>
    <Person>
    <FirstName>Elvis</FirstName>
    <LastName>Presley</LastName>
    </Person>

    fazl@ubuntu:~/bin/xslt$ cat szomiz.xsl
    <?xml version="1.0"?>
    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:eek:utput method="text" />

    <xsl:template match="node()">
    <xsl:for-each select="ancestor-or-self::*">
    <xsl:value-of select="concat('/',name())"/>
    </xsl:for-each>
    <xsl:text>
    </xsl:text>

    <xsl:apply-templates select="*"/>
    </xsl:template>

    </xsl:transform>

    fazl@ubuntu:~/bin/xslt$ xsltproc szomiz.xsl Person.xml
    /Person
    /Person/FirstName
    /Person/LastName
    , Jun 21, 2008
    #7
  8. Guest

    On 21 Jun., 16:43, "szomiz" <>
    wrote:
    > <xsl:template match="*">
    >     <xsl:param name="parPath"/>
    >     <xsl:variable name="locPath" select="concat($parPath,'/',name())"/>
    >     <xsl:value-of select="concat($locPath,'
    &#10')"/>
    >     <xsl:apply-templates>
    >         <xsl:with-param name="parPath" select="$locPath"/>
    >     </
    > </


    Well, I don't want to sound too ungrateful but this doesn't really
    appeal over the one I managed to put together (with help from your
    earlier hint - thanks).

    - It's not shorter.
    - Its not simpler.
    - And its not working...

    :)

    Beyond the broken (obviously, even to me) closing tags, semicolons
    seem to be missing in the newline reference.

    In fact, simply replacing my:

    <xsl:text>
    </xsl:text>

    with :

    <xsl:text>
    </xsl:text>

    is enough ( and not only is shorter, it also works :)


    > [node()] = [* or text() or comment() or processing-instrction()]


    This I *didn't* know. So in XSLT, * means something less general than
    node() ?

    I find this less than intuitive, *surprising* is the word.

    But the funniest thing is, to spit out a list of all directories
    under / in unix, all you need type is :

    find / -type d

    Now, XML is basically a tree of elements encoded in text form -- and
    XSLT is supposed to be the 'native' way to process XML, yet it takes
    an 8-line template (embedded inside a four-line wrapper to make it a
    script) to do this simple task.

    (Actually I don't mind the number of lines so much as the fact that it
    just looks greek compared to "list all element xpaths".)

    Am I the only one who suspects there is something rotten in the land
    of XSLT ?
    (Am I going to get flamed for heretical talk ? :)

    Anyway, I'd be interested if anyone can put together a 'better' xslt
    version than below ?
    (Better includes 'shorter', 'easier to understand', but not 'really
    cool AND really cryptic'..).

    fazl@ubuntu:~/bin/xslt$ cat szomiz.xsl
    <?xml version="1.0"?>
    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:eek:utput method="text" />

    <xsl:template match="*">
    <xsl:for-each select="ancestor-or-self::*">
    <xsl:value-of select="concat('/',name())"/>
    </xsl:for-each>
    <xsl:text>
    </xsl:text>
    <xsl:apply-templates select="*"/>
    </xsl:template>
    </xsl:transform>

    fazl@ubuntu:~/bin/xslt$ cat Person.xml
    <?xml version="1.0" standalone='yes'?>
    <Person>
    <FirstName>Elvis</FirstName>
    <LastName>Presley</LastName>
    </Person>

    fazl@ubuntu:~/bin/xslt$ xsltproc szomiz.xsl Person.xml
    /Person
    /Person/FirstName
    /Person/LastName


    Thanks, Fazl
    , Jun 22, 2008
    #8
  9. wrote:
    >
    > I find this less than intuitive, *surprising* is the word.
    >
    > But the funniest thing is, to spit out a list of all directories
    > under / in unix, all you need type is :
    >
    > find / -type d
    > (...)
    >
    > Am I the only one who suspects there is something rotten in the land
    > of XSLT ?
    > (Am I going to get flamed for heretical talk ? :)
    >


    If you feel that XSLT might not be the best choice for this task, you could give it a try with xmlgawk and use the one-liner (half-liner ;-) posted earlier by Juergen:

    xgawk -lxml 'XMLSTARTELEM {print XMLPATH}'

    For me, this comes closest to your find command example.

    Hermann
    Hermann Peifer, Jun 23, 2008
    #9
  10. Peter Flynn Guest

    wrote:
    > On 20 Jun., 18:16, Martin Honnen <> wrote:
    >> Well what do you want to generate if there are namespaces used? What do
    >> you want to generate if there are several FirstName and/or LastName
    >> child elements?

    >
    > I think I'd like to see this kind of output (if these elements are in
    > a namespace Foo)
    >
    > Eg:
    >
    > /
    > /Foo:person
    > /Foo:person/FirstName
    > /Foo:person/LastName
    >
    > If there are several child elements, I want to see them all listed in
    > document order.
    >
    > -Fazl


    If you don't have xmlgawk, this works with SP and regular awk or gawk:

    $ onsgmls -wxml xml.dcl myfile.xml | grep '^[()]' | awk '/\(/ {path=path
    "/" substr($0,2)} /\)/ {x=gsub("/[^/]+$","",path)} {print path}'

    ///Peter
    --
    XML FAQ: http://xml.silmaril.ie
    Peter Flynn, Jun 24, 2008
    #10
  11. A pseudo-XPath generator in XSLT appears in part 2 of my "styling
    stylesheets" article on DeveloperWorks. (Making it a real XPath
    generator requires dealing properly with namespaces, which isn't bad but
    which was beyond the scope of what I wanted to show at that time.)

    http://www.ibm.com/developerworks/xml/library/x-styless2/
    Joseph J. Kesselman, Jun 24, 2008
    #11
  12. Martin Honnen wrote:
    > Well what do you want to generate if there are namespaces used?


    The portable answer would be to move the name tests into the predicates,
    using something like *[localname()="bar" and
    namespaceuri()="http://my-ns"] (or @*[....] for an attribute, of
    course). More than I wanted to explain in the original article, and the
    editors couldn't be persuaded to let me go back and attach a sidebar later.

    > What do you want to generate if there are several FirstName and/or LastName
    > child elements?


    The generator I pointed to does the right thing in that regard by
    attaching a positional predicate to distinguish which one was intended.
    Joseph J. Kesselman, Jun 24, 2008
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Noah
    Replies:
    5
    Views:
    778
  2. Adam Hartshorne
    Replies:
    2
    Views:
    372
    Nitin Motgi
    Jan 27, 2006
  3. Bart Plessers \(artabel\)

    create foldertree from list of full paths, how?

    Bart Plessers \(artabel\), Sep 30, 2003, in forum: ASP General
    Replies:
    0
    Views:
    119
    Bart Plessers \(artabel\)
    Sep 30, 2003
  4. Ohad Lutzky

    Paths, gentleman, paths

    Ohad Lutzky, Nov 6, 2006, in forum: Ruby
    Replies:
    2
    Views:
    187
    David Vallner
    Nov 7, 2006
  5. Neil Shadrach
    Replies:
    2
    Views:
    389
    Neil Shadrach
    Oct 28, 2003
Loading...

Share This Page