过滤XML节点

问题描述:

我有类似这样的XML文件(除去更多的节点和细节):过滤XML节点

<?xml version="1.0" encoding="utf-8"?> 
<Message xmlns="http://www.theia.org.uk/ILR/2011-12/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
<Header> 
    <CollectionDetails> 
     <Collection>ILR</Collection> 
     <Year>1112</Year> 
     <FilePreparationDate>2011-10-06</FilePreparationDate> 
    </CollectionDetails> 
    <Source> 
     <ProtectiveMarking>PROTECT-PRIVATE</ProtectiveMarking>   
    </Source> 
</Header> 
<SourceFiles> 
    <SourceFile> 
     <SourceFileName>A10004705001112004401.ER</SourceFileName> 
     <FilePreparationDate>2011-10-05</FilePreparationDate> 
    </SourceFile> 
</SourceFiles> 
<LearningProvider> 
    <UKPRN>10004705</UKPRN> 
    <UPIN>107949</UPIN> 
</LearningProvider> 
<Learner> 
    <ULN>4682272097</ULN> 
    <GivenNames>Peter</GivenNames> 
    <LearningDelivery> 
     <LearnAimRef>60000776</LearnAimRef>   
    </LearningDelivery>  
    <LearningDelivery> 
     <LearnAimRef>ZPROG001</LearnAimRef>   
    </LearningDelivery> 
</Learner> 
<Learner> 
    <ULN>3072094321</ULN>  
    <GivenNames>Thomas</GivenNames>  
    <LearningDelivery> 
     <LearnAimRef>10055320</LearnAimRef>   
    </LearningDelivery> 
    <LearningDelivery> 
     <LearnAimRef>10002856</LearnAimRef>   
    </LearningDelivery> 
    <LearningDelivery> 
     <LearnAimRef>1000287X</LearnAimRef>   
    </LearningDelivery> 
</Learner> 
</Message> 

我需要过滤此,使得有孩子的LearningDelivery LearnAimRef只有学习者记录ZPROG001将显示所以在这种情况下,输出将是第一个学生,但不是第二:

<?xml version="1.0" encoding="utf-8"?> 
<Message xmlns="http://www.theia.org.uk/ILR/2011-12/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
<Header> 
    <CollectionDetails> 
     <Collection>ILR</Collection> 
     <Year>1112</Year> 
     <FilePreparationDate>2011-10-06</FilePreparationDate> 
    </CollectionDetails> 
    <Source> 
     <ProtectiveMarking>PROTECT-PRIVATE</ProtectiveMarking>   
    </Source> 
</Header> 
<SourceFiles> 
    <SourceFile> 
     <SourceFileName>A10004705001112004401.ER</SourceFileName> 
     <FilePreparationDate>2011-10-05</FilePreparationDate> 
    </SourceFile> 
</SourceFiles> 
<LearningProvider> 
    <UKPRN>10004705</UKPRN> 
    <UPIN>107949</UPIN> 
</LearningProvider> 
<Learner> 
    <ULN>4682272097</ULN> 
    <GivenNames>Peter</GivenNames> 
    <LearningDelivery> 
     <LearnAimRef>60000776</LearnAimRef>   
    </LearningDelivery>  
    <LearningDelivery> 
     <LearnAimRef>ZPROG001</LearnAimRef>   
    </LearningDelivery> 
</Learner> 
</Message> 

我已经调查如何做到这一点,并认为正确的方式做,这是使用XSL转换过程xml和根据需要输出到一个新文件(在c#中执行此操作)。经过几个小时试图围绕XSLT语法包装我的头,我仍然卡住,无法获得我想要的输出。任何帮助非常感谢。

要复制大多数XML源文档的,仅修改某些部分,你将要开始与一个恒等变换。这只是复制一切。然后添加一个模板覆盖的身份模板,你不想复制<Learner>元素:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:theia="http://www.theia.org.uk/ILR/2011-12/1"> 
    <!-- identity template --> 
    <xsl:template match="@* | node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
    </xsl:template> 
    <!-- override the above template for certain Learner elements; output nothing. --> 
    <xsl:template match="theia:Learner[ 
    not(theia:LearningDelivery/theia:LearnAimRef = 'ZPROG001')]"> 
    </xsl:template> 
</xsl:stylesheet> 

(借款命名空间从@andyb前缀)。

+1

+1为一个很好的答案。 –

+0

优秀的答案,这正是我想要的。我希望我能更多地理解XSLT,但它对我来说只是一次。 – PeteT

如果你只是希望所有具有后代(在这种情况下LearnAimRef)的<Learner>元素与特定的值,那么你可以使用一个谓词表达式([]之间的位)来过滤节点集合。

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:theia="http://www.theia.org.uk/ILR/2011-12/1"> 
<xsl:template match="/theia:Message"> 
    <xsl:copy-of select="theia:Learner[theia:LearningDelivery/theia:LearnAimRef='ZPROG001']"/> 
</xsl:template> 
</xsl:stylesheet> 

所以copy-of全文复制所有学习者的节点,有一个叫LearningDelivery孩子其中有一个叫LearnAimRef的孩子,有等于ZPROG001

你的XML文档中的值具有default namespace的“http://www.theia.org.uk/ILR/2011-12/1”,所以为了让XPath正确选择一个节点,它必须使用相同的名称空间声明,因此在上面的XSLT中,我已将您的名称空间分配给别名,并在XPath中使用它。

如果你想在XML源复制到输出树的其他部分,你可以添加更多的规则,例如<xsl:copy-of select="theia:LearningProvider"/>

这不是在C#应用转换的答案,但是这已经被回答 - How to apply an XSLT Stylesheet in C#

希望这有助于:)

+0

在展示如何选择所需的学习者元素方面做得很好,特别是在命名空间问题上。然而,OP在他期望的输出中显示他希望复制大部分文档;只有''没有正确内容的元素将被忽略。 – LarsH

+0

是的,我提到了在答案中复制更多节点并且XSLT不完整。 +1为你更清洁和更完整的答案。 – andyb

+0

感谢您的回答,我已经制定了C#方面的事情,这是我遇到的实际XSLT文件。 – PeteT