我正在努力寻找最好(有效)的方法。
我有一个中等大小的XML文档。根据具体设置,出于安全原因,需要过滤掉它的某些部分。
我将在XSLT中执行此操作,因为它是可配置的,不需要更改任何代码。
我环顾四周,但没有太多运气。
例如:
我有以下XPath:
//*[@root='2.16.840.1.113883.3.51.1.1.6.1']
Whicrooth为我提供了根属性等于特定OID的所有节点。在这些节点中,我希望删除除少数(例如 foo 和 bar )之外的所有属性,然后添加另一个属性(例如原因< /强>)
对于具有特定属性的节点,我还需要有多个XPath表达式,这些表达式可以在特定节点上运行为零,并以类似的方式清除它的内容。
我正在玩来自的信息:
XPath expression to select all XML child nodes except a specific list?
和Remove Elements and/or Attributes by Name per XSL Parameters
当我能够访问到目前为止所做的事情时,我会很快更新。
示例:
转换前的XML。 更新:我想过滤掉扩展,然后过滤文档中与该扩展属性值匹配的所有值:
<root>
<childNode>
<innerChild root="2.16.840.1.113883.3.51.1.1.6.1" extension="123" type="innerChildness"/>
<innerChildSibling/>
</childNode>
<animals>
<cat>
<name>123</name>
</cat>
</animals>
<tree/>
<water root="2.16.840.1.113883.3.51.1.1.6.1" extension="1223" type="liquidLIke"/>
</root>
在
<root>
<childNode>
<innerChild root="2.16.840.1.113883.3.51.1.1.6.1" flavor="MSK"/> <!-- filtered -->
<innerChildSibling/>
</childNode>
<animals>
<cat>
<name>****</name>
</cat> <!-- cat was filtered -->
</animals>
<tree/>
<water root="2.16.840.1.113883.3.51.1.1.6.1" flavor="MSK"/> <!-- filtered -->
</root>
我可以使用XSLT2。
我正在尝试这个没有任何运气(对于初学者)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:param name="OIDAttrToDelete" select="'extension'"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<!-- Get all nodes for the OID -->
<xsl:template match="//*[@root='2.16.840.1.113883.3.51.1.1.6.1']">
<xsl:if test="name() = $OIDAttrToDelete">
<xsl:attribute name="nullFlavor">MSK</xsl:attribute>
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:2)
<xsl:param name="OIDAttrToDelete" select="'extension'" />
<xsl:template match="* | node()">
<xsl:copy>
<xsl:apply-templates select="* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="@*">
<xsl:choose>
<xsl:when test="../@root = '2.16.840.1.113883.3.51.1.1.6.1'">
<xsl:copy-of select=".[not(contains($OIDAttrToDelete, name()))]" />
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select=".">
</xsl:otherwise>
</xsl:choose>
</xsl:template>
注意:
我创建了一个仅匹配属性的模板,并决定是否复制它们。这样我就不必非常干涉身份模板了。
无需为身份模板指定名称。只需使用适当的select表达式调用<apply-templates>
,处理器就会自动调用它。
模板中的匹配表达式不是完整的XPath表达式。您无需匹配//*[predicate]
。使用*[predicate]
就足够了。
如果您担心安全问题,我会改为使用白名单($OIDAttrToKeep
)。
如果$OIDAttrToDelete
是值列表(例如以逗号分隔),则应在测试中包含分隔符:
.[
not(
contains(
concat(',', $OIDAttrToDelete, ','),
concat(',', name(), ',')
)
)
]
以避免部分名称匹配。
如果您的父OID应该是可配置的,您可以使用相同的技术:
<xsl:template match="@*">
<xsl:choose>
<xsl:when test="
contains(
concat(',', $OIDToStrip, ','),
concat(',', ../@root, ',')
)
">
<!-- ... -->
</xsl:when>
</xsl:choose>
</xsl:template>
答案 1 :(得分:2)
这是一个完整的XSLT 2.0转换,根据外部参数,它标识具有特定属性名称和值的元素,并且对于每个这样的元素,删除所有未列入白名单的属性并添加其他指定的属性强>:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="vFilters">
<filter>
<markerAttribute name="root">2.16.840.1.113883.3.51.1.1.6.1</markerAttribute>
<whiteListedAttributes>
<name>root</name>
<name>foo</name>
</whiteListedAttributes>
<addAtributes flavor="MSK" reason="Demo"/>
</filter>
</xsl:param>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"*[for $cur in .,
$m in $vFilters/filter/markerAttribute
return
$cur/@*[name() eq $m/@name and . eq $m]
]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:copy-of select=
"for $m
in $vFilters/filter/markerAttribute
return
if(current()/@*
[name() eq $m/@name
and
. eq $m
])
then
$m/../addAtributes/@*
else ()
"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"@*[for $cur in .,
$p in ..,
$m in $vFilters/filter/markerAttribute
return
$p/@*[name() eq $m/@name and . eq $m]
and
not(name($cur) = $m/../whiteListedAttributes/name)
]
"/>
</xsl:stylesheet>
将此转换应用于以下XML文档(基于提供的,但添加了一个列入白名单的属性):
<root>
<childNode>
<innerChild root="2.16.840.1.113883.3.51.1.1.6.1"
a="b" b="c" foo="bar" type="innerChildness"/>
<innerChildSibling/>
</childNode>
<animals>
<cat>
<name>bob</name>
</cat>
</animals>
<tree/>
<water root="2.16.840.1.113883.3.51.1.1.6.1"
z="zed" l="ell" type="liquidLIke"/>
</root>
生成所需的正确结果 - 在已标识的元素上删除所有未列入白名单的属性,并添加过滤器中指定的两个新属性:
<root>
<childNode>
<innerChild root="2.16.840.1.113883.3.51.1.1.6.1" foo="bar" flavor="MSK" reason="Demo"/>
<innerChildSibling/>
</childNode>
<animals>
<cat>
<name>bob</name>
</cat>
</animals>
<tree/>
<water root="2.16.840.1.113883.3.51.1.1.6.1" flavor="MSK" reason="Demo"/>
</root>
<强>解释强>:
外部参数$vFilters
可以包含一个或多个过滤器,如下所示:
<filter>
<markerAttribute name="root">2.16.840.1.113883.3.51.1.1.6.1</markerAttribute>
<whiteListedAttributes>
<name>root</name>
<name>foo</name>
</whiteListedAttributes>
<addAtributes flavor="MSK" reason="Demo"/>
</filter>
markerAttribute
元素指定标识属性的名称和值。在这种情况下,过滤器标识(适用于)root
属性值为"2.16.840.1.113883.3.51.1.1.6.1"
的元素。
此过滤器中指定了两个列入白名单的属性名称:root
和foo
。
将在此过滤器元素标识的每个属性上添加两个具有指定值的新属性:flavor="MSK"
和reason="Demo"
。
外部参数$vFilters
可以包含许多过滤器,每个过滤器都标识不同的“类型”元素,并指定一组不同的白名单属性名称和要添加的新属性。