Фильтр XML на основе дочерних узлов - PullRequest
4 голосов
/ 07 октября 2011

У меня есть 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, я все еще застрял и не могу получить желаемый результат.Любая помощь высоко ценится.

Ответы [ 2 ]

5 голосов
/ 07 октября 2011

Чтобы скопировать большую часть исходного документа 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 голос
/ 07 октября 2011

Если вы хотите, чтобы все элементы <Learner> имели потомок (в данном случае LearnAimRef ) с определенным значением, тогда вы можете использовать выражение предиката (бит между [ и ]) для фильтрации набора узлов.

<?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 читается как , копирует все узлы Learner, у которых есть дочерний элемент с именем LearningDelivery, у которого есть дочерний элемент с именем LearnAimRef, у которого естьзначение, равное ZPROG001

Ваш XML-документ имеет пространство имен по умолчанию , равное "http://www.theia.org.uk/ILR/2011-12/1", поэтому для правильного выбора узла в XPath необходимо использоватьто же самое объявление пространства имен, поэтому в приведенном выше XSLT я назначил ваше пространство имен псевдониму и использовал его в XPath.

Если вы хотите, чтобы другие части исходного XML-источника копировались в выходное дерево, вы можете добавитьдругие правила, например <xsl:copy-of select="theia:LearningProvider"/>

Это не ответ на вопрос о применении преобразования в C #, однако на него уже дан ответ - Как применить таблицу стилей XSLT в C #

Надеюсь, это поможет:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...