我想使用XSLT更新XML中的一些节点。喜欢联系方式和电子邮件。 目前我使用的命令如下:
<xsl:template match="@*|node()*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/Metadata/contact/node/Email">
<xsl:variable name="OName" select="/Metadata/contact/organisationName/CharacterString"/>
<xsl:variable name="Email" select="/Metadata/contact/node/Email/CharacterString"/>
<xsl:choose>
<xsl:when test="contains($OName,'TestOrg')">
<CharacterString>
<xsl:value-of select="'test@Test.com'"/>
</CharacterString>
</xsl:when>
<xsl:otherwise>
<CharacterString>
<xsl:value-of select="$Email"/>
</CharacterString>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
由于Contact节点是多个,并且在每个Contact节点中都有一个组织名称和电子邮件ID。对于ex联系节点是3,目前它在$ OName变量和$ Email变量中获取3个值,因此节点不匹配。那么如何使用XSLT只更新xml中的某些节点?
答案 0 :(得分:1)
您拥有的第一个模板是所谓的“Identity template”,它将遍历您的完整源XML:
<xsl:template match="@*|node()*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
您拥有的第二个模板将在每个/Metadata/contact/node/Email
上匹配。我会写这个模板有点不同。我认为最好匹配Email/CharacterString
节点,然后执行您的操作,而不是匹配绝对路径。
我会使用如下模板:
<xsl:template match="Email/CharacterString">
<xsl:copy>
<xsl:choose>
<xsl:when test="contains(ancestor::contact/organisationName/CharacterString,'TestOrg')">
<xsl:value-of select="'test@Test.com'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
以上模板仅匹配您要更改的节点(Email/CharacterString
)。匹配xsl:copy
后,复制当前所选节点(CharacterString
)。该值将根据ancestor::contact/organisationName/CharacterString
的值填充。我正在使用XPath Axe ancestor
。这在更改模板时会很方便。
如果我现在要更改模板,例如只选择我想要更改的联系节点,则第二个模板可以写为:
<xsl:template match="contact[organisationRole/CharacterString = '1']/node/Email/CharacterString">
<xsl:copy>
<xsl:choose>
<xsl:when test="contains(ancestor::contact/organisationName/CharacterString,'TestOrg')">
<xsl:value-of select="'test@Test.com'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
这里我只将模板应用于contact
个节点,其中[]
organisationRole/CharacterString
等于值1.请注意,模板的主体没有变化。因此,您可以看到为什么使用XPath Axe是有用的。
完成XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<!-- Identity template -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="contact[organisationRole/CharacterString = '1']/node/Email/CharacterString">
<xsl:copy>
<xsl:choose>
<xsl:when test="contains(ancestor::contact/organisationName/CharacterString,'TestOrg')">
<xsl:value-of select="'test@Test.com'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
源XML
<?xml version="1.0" encoding="UTF-8"?>
<Metadata>
<contact>
<organisationRole>
<CharacterString>1</CharacterString>
</organisationRole>
<organisationName>
<CharacterString>TestOrg</CharacterString>
</organisationName>
<postalCode>
<CharacterString>2020</CharacterString>
</postalCode>
<node>
<Email>
<CharacterString>some@user.com</CharacterString>
</Email>
</node>
</contact>
<contact>
<organisationRole>
<CharacterString>2</CharacterString>
</organisationRole>
<organisationName>
<CharacterString>Example Org</CharacterString>
</organisationName>
<postalCode>
<CharacterString>8080</CharacterString>
</postalCode>
<node>
<Email>
<CharacterString>somebody@else.com</CharacterString>
</Email>
</node>
</contact>
<contact>
<organisationRole>
<CharacterString>1</CharacterString>
</organisationRole>
<organisationName>
<CharacterString>Real Org</CharacterString>
</organisationName>
<postalCode>
<CharacterString>9050</CharacterString>
</postalCode>
<node>
<Email>
<CharacterString>user@example.com</CharacterString>
</Email>
</node>
</contact>
</Metadata>
制作输出
<?xml version="1.0" encoding="UTF-8"?>
<Metadata>
<contact>
<organisationRole>
<CharacterString>1</CharacterString>
</organisationRole>
<organisationName>
<CharacterString>TestOrg</CharacterString>
</organisationName>
<postalCode>
<CharacterString>2020</CharacterString>
</postalCode>
<node>
<Email>
<CharacterString>test@Test.com</CharacterString>
</Email>
</node>
</contact>
<contact>
<organisationRole>
<CharacterString>2</CharacterString>
</organisationRole>
<organisationName>
<CharacterString>Example Org</CharacterString>
</organisationName>
<postalCode>
<CharacterString>8080</CharacterString>
</postalCode>
<node>
<Email>
<CharacterString>somebody@else.com</CharacterString>
</Email>
</node>
</contact>
<contact>
<organisationRole>
<CharacterString>1</CharacterString>
</organisationRole>
<organisationName>
<CharacterString>Real Org</CharacterString>
</organisationName>
<postalCode>
<CharacterString>9050</CharacterString>
</postalCode>
<node>
<Email>
<CharacterString>user@example.com</CharacterString>
</Email>
</node>
</contact>
</Metadata>
修改强>
如果您只想更改Email/CharacterString
包含文本organisationName/CharacterString
的联系人中的TestOrg
,则XSLT将如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<!-- Identity template -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="contact[contains(organisationName/CharacterString,'TestOrg')]/node/Email/CharacterString">
<xsl:copy>
<xsl:value-of select="'test@Test.com'"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:0)
根据您的描述,您的变量似乎需要相对于模板的上下文节点:
<xsl:template match="/Metadata/contact/node/Email">
<xsl:variable name="OName" select="../../organisationName/CharacterString"/>
<xsl:variable name="Email" select="CharacterString"/>
否则,您将始终从根节点开始为模板的每个匹配选择,并且每次都会选择所有现有的联系节点。