I’m struggling with accessing information inside xs:appinfo element using XPath
I have another well-structured XML inside an xs:appinfo element. Is there a way to directly access a certain element of that XML within the xs:appinfo using XPath? Or is everything within xs:appinfo interpreted as pure text only?
Sample XL Schema:
<xs:schema targetNamespace="ts" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="MyElement">
<xs:complexType>
<xs:sequence>
<xs:element name="MyChildElement1" type="xs:string"/>
<xs:element name="MyChildElement2" type="xs:string">
<xs:annotation>
<xs:appinfo>
<AppInfoElement1>Hello</AppInfoElement1>
<AppInfoElement2>Hello</AppInfoElement2>
</xs:appinfo>
<xs:documentation xml:lang="en">Any documentation</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
How can I access the text of AppInfoElement2 inside the appinfo using XPath?
I tried the following:
//xs:annotation/xs:appinfo[.]
//xs:annotation/xs:appinfo/AppInfoElement2[text()]
Actually I run the XPath in an XSLT select statement as follows (I thought this does not make a difference, but none of the proposed answers work for me):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//*[@name='MyChildElement2']" >
<xsl:copy-of select="xs:annotation/xs:appinfo/AppInfoElement2/text()" />
</xsl:template>
</xsl:stylesheet>
I’m using a simple C# application to test this.
8
This XPath,
//AppInfoElement2/text()
will select all text
node children of all AppInfoElement2
elements in the document.
By using //
, you bypass the namespaced elements. Should you ever need to specify namespaced elements in your XPath, see How does XPath deal with XML namespaces?
1
Your second attempt works for me:
//xs:annotation/xs:appinfo/AppInfoElement2[text()]
Result:
<AppInfoElement2 xmlns:xs="http://www.w3.org/2001/XMLSchema">Hello</AppInfoElement2>
So if it’s not working for you then there’s something wrong not in the XPath but in the way you are invoking it, i.e. in the host environment in which the XPath expression is evaluated. Perhaps you’re not providing the XPath interpreter with a namespace binding for the prefix xs
? How you do that is dependent on the host language or platform environment (which you haven’t mentioned).
Otherwise, as @kjhughes says, you could just omit the xs:
-namespaced elements from your XPath expression:
//AppInfoElement2[text()]
Though this wouldn’t be workable if you wanted to distinguish between AppInfoElement2
elements which appeared within different xs:element
elements, where you would need a more specific query e.g.:
//xs:element[@name='MyElement']
//xs:element[@name='MyChildElement2']
//xs:annotation/xs:appinfo/AppInfoElement2[text()]
EDIT #2:
I’d expect your stylesheet to copy the document but replace this section with the text “hello”:
<xs:element name="MyChildElement2" type="xs:string">
<xs:annotation>
<xs:appinfo>
<AppInfoElement1>Hello</AppInfoElement1>
<AppInfoElement2>Hello</AppInfoElement2>
</xs:appinfo>
<xs:documentation xml:lang="en">Any documentation</xs:documentation>
</xs:annotation>
</xs:element>
What do you actually want it to do, though?
2