how to iterate only first level node in xml with x-path?
I need to iterate through an XML file. The root node has a few children and I need to either copy the child as is or to do something. So I'm working on an XSLT to do so. Here's a sample source XML:
<?xml version="1.0" encoding="utf-8"?>
<XDSDocumentEntry id="DOC01">
<author authorRole="XDSITEST_DICOM_INSTANCE_PUBLISHER" authorPerson="XDSITEST">Author</author>
<classCode displayName="Communication" codingScheme="Connect-a-thon classCodes">Communication</classCode>
<confidentialityCode displayName="Celebrity" codingScheme="Connect-a-thon confidentialityCodes">
</XDSDocumentEntry>
In this XML I need to select nodes author, classCode and confidentialityCodes but I'm getting the text() nodes with this code:
<xsl:for-each select="node()"><!--<xsl:copy-of select="."/>-->
<!--<xsl:value-of select="local-name()"/>-->
<xsl:choose>
<xsl:when test="author">
do something
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
My result so far is this:
author<author authorRole="XDSITEST_DICOM_INSTANCE_PUBLISHER" authorPerson="XDSITEST"
authorInstitution="Some institution"/>
classCode<classCode displayName="Communication" codingScheme="Connect-a-thon classCodes">Communication</classCode>
confidentialityCode<confidentialityCode displayName="Celebrity" codingScheme="Connect-a-thon confidentialityCodes">
C</confidentialityCode>
Any hint? Thx.
EDIT
Sorry, had an error (I removed ).
Actually, why am I using the for-each is because I need the document exactly as it was except for a few nodes. In the example above the final output should look like this:
<?xml version="1.0" encoding="UTF-8"?>
<XDSDocumentEntry>
<author authorRole="XDSITEST_DICOM_INSTANCE_PUBLISHER" authorPerson="XDSITEST"
authorInstitution="Some institution"/>
<author>
<authorInstitution>
<organizationName>Some institution</organizationName>
</authorInstitution>
<authorRole>XDSITEST_DICOM_INSTANCE_PUBLISHER</authorRole>
<authorPerson>
<assigningAuthorityName>XDSITEST</assigningAuthorityName>
</authorPerson>
</author>
<classCode displayName="Communication" codingScheme="Connect-a-thon classCodes">Communication</classCode>
<confidentialityCode displayName="Celebrity" codingScheme="Connect-a-thon confidentialityCodes">
C</confidentialityCode>
</XDSDocumentEntry>
EDIT 2
I created this template as suggested by @Martin. But still how do I select the node name 'author'??
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:choose>
<xsl:when t开发者_如何学Cest="local-name()=author">
a
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="node()|@*"/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
It is hard to tell what goes wrong without knowing the context node of your for-each
. I would suggest you forget about for-each
and instead start writing templates e.g.
<xsl:template match="XDSDocumentEntry/*">
<!-- output here what you want to output for child elements of XDSDocumentEntry -->
</xsl:template>
<xsl:template match="XDSDocumentEntry/author">
<!-- put needed special treatement of author element here -->
</xsl:template>
If you still have problems then show us what kind of output you want to create for the sample input you posted, then we can help with the proper XSLT code.
[edit] If all you want is copying nodes besides the child nodes of the author element then two templates suffice:
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="XDSDocumentEntry/author">
<xsl:copy>
<xsl:apply-templates select="@*"/>
</xsl:copy>
</xsl:template>
This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="author/node()"/>
<xsl:template match="author">
<xsl:call-template name="identity"/>
<xsl:copy>
<xsl:apply-templates select="@*" mode="element"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*" mode="element">
<xsl:element name="{name()}">
<xsl:apply-templates select="." mode="value"/>
</xsl:element>
</xsl:template>
<xsl:template match="author/@authorPerson" mode="value">
<assigningAuthorityName>
<xsl:value-of select="."/>
</assigningAuthorityName>
</xsl:template>
</xsl:stylesheet>
Output:
<XDSDocumentEntry id="DOC01">
<author authorRole="XDSITEST_DICOM_INSTANCE_PUBLISHER" authorPerson="XDSITEST"></author>
<author>
<authorRole>XDSITEST_DICOM_INSTANCE_PUBLISHER</authorRole>
<authorPerson>
<assigningAuthorityName>XDSITEST</assigningAuthorityName>
</authorPerson>
</author>
<classCode displayName="Communication" codingScheme="Connect-a-thon classCodes">Communication</classCode>
<confidentialityCode displayName="Celebrity" codingScheme="Connect-a-thon confidentialityCodes"></confidentialityCode>
</XDSDocumentEntry>
I created this template as suggested by @Martin. But still how do I select the node name 'author'??
Answer:
You do not select. Instead, you override the identity template with a more specific template that matches exactly the node(s) (in your case the author
element, for which you want a different processing than simply copy "as-is":
<xsl:template match="author">
<!-- Put your specific code here -->
</xsl:template>
Using and overriding the identity rule is the most fundamental and powerful XSLT design pattern. Read more about it here.
精彩评论