Namespace agnostic XPath query with element content

a 夏天 提交于 2019-11-30 05:10:12

问题


The namespace agnostic syntax I've seen around is confusing me.

Say I have:

<root>
  <parent attribute="A">A<child>A</child></parent>
  <parent attribute="B">B<child>B</child></parent>
</root>

So far I see how:

/root/parent/child/text()

translates to:

/*[local-name()='root']/*[local-name()='parent']/*[local-name()='child']/text()

but i'm struggling with things like this:

/root/parent[@attribute="A"]/child/text()

or:

/root/parent[text()="B"]/child/text()

or:

/root/parent[1]/child/text()

How do these translate?

Thanks,

EDIT: One More :-)

<root>
        <parent>
            <childName>serverName</childName>
            <childValue>MyServer</childValue>
        </parent>
        <parent>
            <childName>ServerLocation</childName>
            <childValue>Somewhere</childValue>
         </parent>
</root>

How does this translate?

/root/parent[childName="serverName"]/childValue/text()

回答1:


The namespace agnostic syntax I've seen around is confusing me.

First, I would advise you not to use this syntax, especially if it is confusing. It can also result in errors -- see the end of my answer for details.

The standard way to specify in an XPath expression names that are in a namespace is to register a namespace with your XPath engine (see the respective, vendor-specific documentation) and then to use the prefix bound to the registered namespace (say "x") with names like x:someName

There are plenty of good answers on this topic -- jus t use one of them.

Now, if due to some reason you still decide to use the confusing syntax, then:

but i'm struggling with things like this:

/root/parent[@attribute="A"]/child/text()

Use:

/*[local-name()='root']/*[local-name()='parent' and @attribute='A']

then:

or:

/root/parent[text()="B"]/child/text()

Use:

/*[local-name()='root']/*[local-name()='parent' and text()='B']
                                    /*[local-name()='child']/text()

then:

or:

/root/parent[1]/child/text()

Use:

/*[local-name()='root']/*[local-name()='parent'][1]
                                 /*[local-name()='child']/text()

then:

One More :-)

<root>
  <parent>
      <childName>serverName</childName>
      <childValue>MyServer</childValue>
  </parent>
  <parent>
      <childName>ServerLocation</childName>
      <childValue>Somewhere</childValue>
  </parent>
</root>

How does this translate?

/root/parent[childName="serverName"]/childValue/text()

Use:

/*[local-name()='root']
      /*[local-name()='parent'][*[local-name()='childName"]='serverName']
                                           /*[local-name()='childValue']/text()

Do note:

Such expressions may not select the wanted nodes if in the XML documents there are elements with the same local-name that belong to two different namespaces.




回答2:


I understand your question to mean, how do I make these XPath expressions namespace-agnostic? (It's not a special syntax, just a typical use of the local-name() function.)

/root/parent[@attribute="A"]/child/text()

would become

/*[local-name()='root']/*[local-name()='parent'][@attribute='A']/*[local-name()='child']/text()

(You could use double-quotes for the attribute value if you want, but that would make it harder to embed in XSLT or whatever your environment is.)

/root/parent[text()="B"]/child/text()

would become

/*[local-name()='root']/*[local-name()='parent'][text() = 'B']/*[local-name()='child']/text()

And

/root/parent[1]/child/text()

would become

/*[local-name()='root']/*[local-name()='parent'][1]/*[local-name()='child']/text()


来源:https://stackoverflow.com/questions/4953280/namespace-agnostic-xpath-query-with-element-content

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!