xml XSLT:使用多个 or'd 模板匹配来应用模板
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13316970/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
XSLT: use multiple or'd template matches to apply-templates
提问by delliottg
I have an XML with multiple nodes with similar data in each. I want to delete a specific attribute from each node (USER:IPADDRESS). I've figured out how to chain together a number of elements using ors, simply leaving out the User="{@User}" match so it doesn't show up in the results:
我有一个带有多个节点的 XML,每个节点都有相似的数据。我想从每个节点 (USER:IPADDRESS) 中删除一个特定的属性。我已经想出了如何使用 ors 将多个元素链接在一起,只需省略 User="{@User}" 匹配项,这样它就不会出现在结果中:
XSL Snippet:
XSL 片段:
<xsl:template match="Creation | Test | Assignment | Modification | Repair | Termination">
<Creation CommitID="{@CommitID}" Date="{@Date}" BoardID="{@BoardID}">
<xsl:apply-templates/>
</Creation>
</xsl:template>
Unsurprisingly, all of the node names after "Creation" get re-named to Creation because that's what I'm telling it to do. How do I pass in the various matches so they're applied in the proper order in the results? I know I can do a brute force way using identical XSL statements for each of the various matches (that's how I did it the first time), but there must be a more elegant method, it's just evading me. I have millions & millions of lines of XML to process and this is just the first of many transforms I'm going to have to make.
不出所料,“Creation”之后的所有节点名称都被重命名为 Creation,因为这就是我要它做的事情。我如何传入各种匹配项,以便在结果中以正确的顺序应用它们?我知道我可以对各种匹配项中的每一个使用相同的 XSL 语句(这就是我第一次这样做的方式),但必须有一种更优雅的方法,它只是在逃避我。我有数百万行 XML 需要处理,这只是我必须进行的众多转换中的第一个。
I'm using msxsl V4.0 on a Win7 box to do my transforms if that's of any consequence.
如果有任何后果,我将在 Win7 机器上使用 msxsl V4.0 进行转换。
XML:
XML:
<?xml version="1.0"?>
<BoardDatabase>
<Board_Data BoardID="1035">
<Creation CommitID="12b" Date="2007-12-07T15:43:51" BoardID="1035" User="CSAGAN:192.168.1.177">
<BoardDrawing>3B</BoardDrawing>
<AssemblyDrawing>2010F</AssemblyDrawing>
<Notes>PO Num 1959</Notes>
</Creation>
<Test CommitID="117" Date="2007-12-10T10:39:43" BoardID="1035" User="CSAGAN:192.168.1.183">
<ElectricalTestData Result="FAIL" Version="IMM STD REVF">
<AutomatedTest ReportVersion="1.0">
<TestSetup>
<TestAppBuildDate>Dec 07 2007</TestAppBuildDate>
<VersionPath>c:\tests\versions\v12.txt</VersionPath>
<VersionNumber>1.2</VersionNumber>
<OperatorName>CSAGAN</OperatorName>
<StationID>PC-191-NDGrasse</StationID>
<JigSN>12345</JigSN>
<JigAssembly>42</JigAssembly>
<TestStartTime>2007-12-10 10:34:17</TestStartTime>
</TestSetup>
</AutomatedTest>
</ElectricalTestData>
</Test>
<Assignment CommitID="1c1f" User="JRandi:192.168.1.162" Date="2008-09-30T07:36:52" BoardID="1035">
<Notes>Boardset failed etest twice, no problem log entry/repair attempts made.</Notes>
</Assignment>
<Modification CommitID="2bb7" User="JRandi:192.168.1.162" Date="2009-03-11T13:31:21" BoardID="1035">
<AssemblyDrawing>2001G</AssemblyDrawing>
<Notes>Cornelius upgraded boardset to rev. G</Notes>
</Modification>
</Board_Data>
</BoardDatabase>
XSL:
XSL:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="Creation | Test | Assignment | Modification | Repair | Termination">
<Creation CommitID="{@CommitID}" Date="{@Date}" BoardID="{@BoardID}">
<xsl:apply-templates/>
</Creation>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Latest XSL using @DevNull's solution that doubles size of original file:
最新的 XSL 使用 @DevNull 的解决方案,使原始文件的大小加倍:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- Answer from Stack Overflow that only strips out the IP Address from the User attribute. -->
<xsl:template match="@User">
<xsl:attribute name="User">
<xsl:value-of select="substring-before(.,':')"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Latest XSL from @Dimitre's solution that takes a very long time to process (still running after more than 30 minutes, but file is still growing):
来自@Dimitre 解决方案的最新 XSL 需要很长时间来处理(30 多分钟后仍在运行,但文件仍在增长):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"*[contains('|Creation|Test|Assignment|Modification|Repair|Termination|',concat('|', name(), '|'))
]/@user"/>
</xsl:stylesheet>
回答by Daniel Haley
Try changing your template to this:
尝试将您的模板更改为:
<xsl:template match="Creation|Test|Assignment|Modification|Repair|Termination">
<xsl:copy>
<xsl:apply-templates select="@*[not(name()='User')]|node()"/>
</xsl:copy>
</xsl:template>
You'll notice it looks a lot like your identity template with a predicate added to @*.
您会注意到它看起来很像您的身份模板,其中将谓词添加到@*.
Also, if you wanted to strip all Userattributes no matter what the element was, you could use this template instead:
此外,如果您想删除所有User属性,而不管元素是什么,您可以改用此模板:
<xsl:template match="@User"/>
Here's one more way (only stripping from Creationand Testfor brevity)
这里是另一种方式(只剥离Creation并Test为简洁起见)
<xsl:template match="@User[..[self::Creation or self::Test]]"/>
Answer to comment
回复评论
Use this template instead:
请改用此模板:
<xsl:template match="@User">
<xsl:attribute name="User">
<xsl:value-of select="substring-before(.,':')"/>
</xsl:attribute>
</xsl:template>
回答by Dimitre Novatchev
I would use what I consider even a better solution:
我会使用我认为更好的解决方案:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"*[contains('|Creation|Test|Assignment|Modification|Repair|Termination|',
concat('|', name(), '|'))
]/@user"/>
</xsl:stylesheet>
Do note:
请注意:
We only use a single template overriding the identity rule. Its body is empty.
The list of element names is presented as a pipe-delimited string and for long lists this saves significant space -- also, such a string can be passed as an external parameter to the transformation, thus making it maximum generic.
This transformation is in completely "push style".
我们只使用一个模板来覆盖身份规则。它的身体是空的。
元素名称列表显示为管道分隔的字符串,对于长列表,这可以节省大量空间——此外,这样的字符串可以作为外部参数传递给转换,从而使其最大程度地通用。
这种转变完全是“推式”。

