要求是在XML中查找重复元素(BaseName)并使用isDuplicate属性标记父元素(Account)。当输入XML RootElement没有名称空间时,XSL正常工作。当根元素具有命名空间时,我得到空对象。我不确定为什么命名空间导致XSL生成空输出。任何有助于获得正确输出的帮助都将非常感激。
<?xml version="1.0"?>
<objects xmlns="urn:s.sexmaple.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Account>
<Id>001A00F</Id>
<RecordTypeId>012A00</RecordTypeId>
<BaseName>EFGH</BaseName>
</Account>
<Account>
<Id>001A0</Id>
<RecordTypeId>012A0</RecordTypeId>
<BaseName>ABCD</BaseName>
</Account>
<Account>
<Id>001A</Id>
<RecordTypeId>012A</RecordTypeId>
<BaseName>ABCD</BaseName>
</Account>
</objects>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml"
version="1.0"
encoding="UTF-8"
indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="node()|@*">
<xsl:copy copy-namespaces="no">
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="Accounts">
<objects>
<xsl:for-each select="//Account">
<xsl:sort select="BaseName" />
<xsl:apply-templates select="." />
</xsl:for-each>
</objects>
</xsl:variable>
<xsl:variable name="unqentity">
<objects>
<xsl:for-each select="$Accounts/objects/Account">
<xsl:choose>
<xsl:when test="not(following-sibling::Account/BaseName=./BaseName) and not(preceding-sibling::Account/BaseName=./BaseName) ">
<xsl:copy-of select="." />
</xsl:when>
<xsl:otherwise>
<Account>
<xsl:attribute name="isDuplicate">yes</xsl:attribute>
<xsl:for-each select="child::*">
<xsl:element name="{name()}">
<xsl:copy-of select="@*|node()" />
</xsl:element>
</xsl:for-each>
</Account>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</objects>
</xsl:variable>
<xsl:copy-of select="$unqentity" />
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="UTF-8"?>
<objects/>
输入没有命名空间时<?xml version="1.0" encoding="UTF-8"?>
<objects>
<Account>
<Id>001A00F</Id>
<RecordTypeId>012A00</RecordTypeId>
<BaseName>EFGH</BaseName>
</Account>
<Account isDuplicate="yes">
<Id>001A0</Id>
<RecordTypeId>012A0</RecordTypeId>
<BaseName>ABCD</BaseName>
</Account>
<Account isDuplicate="yes">
<Id>001A</Id>
<RecordTypeId>012A</RecordTypeId>
<BaseName>ABCD</BaseName>
</Account>
</objects>
答案 0 :(得分:2)
当你有一个命名空间时,它意味着命名空间中的元素与没有命名空间的元素(或者实际上是不同名称空间中的元素)不同。
这意味着在XSLT中执行此操作...
<xsl:for-each select="//Account">
您正在寻找没有名称空间的帐户元素,因此它与源XML中的帐户元素不匹配,后者位于有趣的标题为“urn”中:s.sexmaple.com“(我怀疑是拼写错误的)
当您使用XSLT2.0时,通过使用 xpath-default-namespace 为任何xpath表达式指定默认命名空间,有一种简单的方法可以解决此问题。通常情况下,这可能就足够了,但是通过在变量中创建新元素会让您稍微复杂一些,然后您可以选择这些元素。
<xsl:for-each select="$Accounts/objects/Account">
这意味着当您在 $ Accounts 变量中创建对象和帐户元素时,它们也需要成为命名空间的一部分
要切入追逐,这就是 xsl:stylesheet 元素需要的样子
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xmlns="urn:s.sexmaple.com"
xpath-default-namespace="urn:s.sexmaple.com">
因此,xpath-default-namespace="urn:s.sexmaple.com"
用于匹配源XML中的元素,而xmlns="urn:s.sexmaple.com"
用于确保您在变量中创建的元素具有此命名空间,并且可以在以后进行匹配。 / p>
说了这么多,你的整个XSLT过于复杂了。您是否只是尝试将 IsDuplicate 属性添加到具有相同 BaseName 的帐户元素?好吧,创建一个键来查找重复项,如此
<xsl:key name="account" match="Account" use="BaseName" />
然后你可以像这样查找重复项:
<xsl:if test="key('account', BaseName)[2]">
<xsl:attribute name="isDuplicate">Yes</xsl:attribute>
</xsl:if>
试试这个XSLT,它应该给出相同的结果
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xpath-default-namespace="urn:s.sexmaple.com">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="account" match="Account" use="BaseName" />
<xsl:template match="Account">
<xsl:copy>
<xsl:if test="key('account', BaseName)[2]">
<xsl:attribute name="isDuplicate">Yes</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
注意这只需要使用xpath-default-namespace
,因为它不是创建全新的元素,只是复制现有元素(也可以复制它们的命名空间)。
答案 1 :(得分:0)
没有命名空间的输入XML工作的原因是具有命名空间的输入XML不是因为输入XML,而是因为XSLT样式表。
当您的XML文件具有默认命名空间时,需要在样式表本身中声明该命名空间。
例如,使用以下XML:
<test xmlns="test.xml.schema">
<element>Content</element>
</test>
当我应用以下XSLT时:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="/">
<out>
<namespace>None</namespace>
<xsl:apply-templates />
</out>
</xsl:template>
<xsl:template match="test">
<test out="True">hello</test>
</xsl:template>
<xsl:template match="*"/>
</xsl:stylesheet>
输出只是:
<out><namespace>None</namespace></out>
<xsl:template match="test">
在输入xml中的test元素上无法匹配,因为它实际上是test.xml.schema:test
,而样式表中没有名称空间的匹配实际上是:test
。因此不可能匹配。
但是,当我们只为输入文档添加命名空间时,请修改模板,如下所示:
<xsl:stylesheet xmlns:t="test.xml.schema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="/">
<out>
<namespace>test.xml.schema</namespace>
<xsl:apply-templates />
</out>
</xsl:template>
<xsl:template match="t:test">
<test out="True">hello</test>
</xsl:template>
<xsl:template match="*"/>
</xsl:stylesheet>
输出变为:
<out xmlns:t="test.xml.schema">
<namespace>test.xml.schema</namespace>
<test out="True">hello</test>
</out>
重要的是要注意输入文档和XSL中的命名空间缩写不需要相同(例如,空白与“t
”),但它们自己的命名空间:(例如,两个空白并且“t
”必须绑定到test.xml.schema
)。
另请注意,using a default namespace in XSLT can be fraught with issues。所以最好在XSLT中使用声明的命名空间。