如何使用x-path仅迭代xml中的第一级节点?

时间:2011-04-20 13:46:52

标签: xml xslt xpath

我需要遍历XML文件。根节点有几个孩子,我需要按原样复制孩子或做一些事情。所以我正在研究一个XSLT。这是一个示例源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>

在此XML中,我需要选择节点作者 classCode confidentialityCodes ,但我正在使用此代码获取text()节点:

        <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>

到目前为止我的结果是:

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>

任何提示? THX。


修改

抱歉,有错误(我已删除)。

实际上,为什么我使用 for-each 是因为除了几个节点之外我完全需要文档。在上面的示例中,最终输出应如下所示:

<?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>

编辑2

我按照@Martin的建议创建了这个模板。但是我如何选择节点名称'author'??

<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:choose>
            <xsl:when test="local-name()=author">
                    a
            </xsl:when>
            <xsl:otherwise>
                <xsl:apply-templates select="node()|@*"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:copy>
</xsl:template>

3 个答案:

答案 0 :(得分:2)

如果不了解for-each的上下文节点,很难说出现了什么问题。我建议你忘记for-each,而是开始编写模板,例如

<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>

如果您仍有问题,请告诉我们您要为您发布的示例输入创建哪种输出,然后我们可以帮助您使用正确的XSLT代码。

[编辑] 如果你想要的只是复制author元素的子节点之外的节点,那么两个模板就足够了:

<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>

答案 1 :(得分:2)

此样式表:

<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>

输出:

<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>

答案 2 :(得分:1)

  

我按照建议创建了这个模板   由@Martin。但我仍然如何选择   节点名称'author'??

回答

选择。相反,您覆盖身份模板,使用更具体的模板,该模板与节点完全匹配(在您的情况下为author元素,您希望进行与简单复制不同的处理“原样“:

<xsl:template match="author">
  <!-- Put your specific code here -->
</xsl:template>

使用和覆盖标识规则是最基本和最强大的XSLT设计模式。阅读更多相关信息here