Выберите уникальные узлы на основе комбинации двух значений атрибута - PullRequest
4 голосов
/ 25 августа 2010

У меня есть XML, который выглядит примерно так:

<Root>
    <Documents>
        <Document id="1"/>
    </Documents>
    <People>
        <Person id="1"/>
        <Person id="2"/>
    </People>
    <Links>
        <Link personId="1" documentId="1"/>
        <Link personId="1" documentId="1"/>
        <Link personId="2" documentId="1"/>
    </Links>
</Root>

И мне интересно получить только элементы «Ссылка», которые имеют уникальную комбинацию «personId's» и «documentId's», поэтому эти две ссылки:

<Root>
    <Links>
        <Link personId="1" documentId="1"/>
        <Link personId="2" documentId="1"/>
    </Links>
</Root>

Как я могу это сделать? Я нашел этот вопрос , хотя я чувствую, что он немного сложнее и может не применяться ... Я предполагаю, что мне понадобится где-нибудь использовать функцию key () ...

Заранее спасибо.

Ответы [ 3 ]

3 голосов
/ 25 августа 2010

Эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kDocAndPeoById" match="Document|Person" use="@id"/>
    <xsl:key name="kLinksByIds" match="Link" 
             use="concat(@personId,'++',@documentId)"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Documents|People|
     Link[count(.|key('kLinksByIds',concat(@personId,'++',@documentId))[1])!=1
          or not(key('kDocAndPeoById',@personId)/self::Person)
          or not(key('kDocAndPeoById',@documentId)/self::Document)]"/>
</xsl:stylesheet>

Выход:

<Root>
    <Links>
        <Link personId="1" documentId="1"></Link>
        <Link personId="2" documentId="1"></Link>
    </Links>
</Root>

Если вас не интересует проверка, есть ли такой Document или Person @id, тогда эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kLinksByIds" match="Link" 
              use="concat(@personId,'++',@documentId)"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Documents|People|
  Link[count(.|key('kLinksByIds',concat(@personId,'++',@documentId))[1])!=1]"/>
</xsl:stylesheet>

Выход:

<Root>
    <Links>
        <Link personId="1" documentId="1"></Link>
        <Link personId="2" documentId="1"></Link>
    </Links>
</Root>
1 голос
/ 25 августа 2010

Вы можете объединить несколько атрибутов селектора в запрос XPath, необязательно быть просто одной парой атрибут = значение.

Поиск по нескольким атрибутам в XML

0 голосов
/ 25 августа 2010

Вам нужно отфильтровать <Link> с чем-то вроде этого, где функция current() возвращает <Link> s, которые вы проверяете на уникальность.

.[not(preceding-sibling::Link[@personId   = current()/@personId and
                              @documentId = current()/@documentId])]

Ось preceding-sibling::раньше находил <Link> элементы, а часть в квадратных скобках проверяет совпадение идентификационных номеров.not(), заключающий в себе все выражение, означает, что все выражение в скобках истинно, только если НЕТ таких предшествующих братьев и сестер не совпадает, т. Е. Не существует предшествующего <Link> с тем же идентификатором человека и документа.так что я оставлю эту часть тебе.Я думаю, что сначала вы найдете все ссылки, скажем, //Link, а затем отфильтруете их на втором шаге с помощью вышеуказанного XPath.Я очень старался, но не мог придумать, как сделать все это за один шаг, так как для этого нужна функция current().

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