оставить только белые элементы и / или атрибуты - PullRequest
0 голосов
/ 29 января 2019

У меня есть XML-файл с множеством узлов, каждый из которых имеет огромное количество атрибутов.Для простоты предположим, что XML выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <header />
  <group>
     <node1 attr1="x" attr2="y" attr3="z" />
     <node2 attr4="x" attr5="y" attr6="z" />
     <node3 attr7="x" attr8="y" attr9="z" />
     <node1 attr1="x" attr2="y" attr3="z" />
  </group>
</root>

Я хотел бы сократить этот XML до уменьшенной версии, сократив содержимое /root/group/, исключив как атрибуты, так и узлы.

  • все узлы с именем node3 должны быть удалены
  • Узлы с именем node1 должны иметь только атрибут attr1
  • Узлы с именем node2 должен иметь только атрибуты attr5 и attr6

Я мог бы написать для этого простой XSLT, используя простой if-match-do-nothing , например.

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:output method="xml" encoding="UTF-8" indent="yes" />

   <xsl:template match="/root/group/node3" />
   <xsl:template match="/root/group/node1/@attr2" />
   <xsl:template match="/root/group/node1/@attr3" />
   <xsl:template match="/root/group/node2/@attr4" />

   <xsl:template match="@*|node()">
     <xsl:copy>
       <xsl:apply-templates select="@*|node()"/>
     </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

Это, однако, не соответствует моим потребностям.Выше указано, что я не хочу, но я хотел бы заявить, что я хочу, используя белый список Два вопроса, которые я нашел, частично ответили на этот вопрос. В одном вопросе введен белый список для узлов, в в другом вопросе введен белый список для атрибутов.Как я могу сделать это элегантно в одном белом списке или есть лучший метод?Можно ли это сделать в белом списке вида:

<whitelist>
  <node1 attr1="" />
  <node2 attr5="" attr6="" />
</whitelist>

Примечание: Я могу использовать только XSLT-1.0

Ожидаемый результат:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <header />
  <group>
     <node1 attr1="x" />
     <node2 attr5="y" attr6="z" />
     <node1 attr1="x" />
  </group>
</root>

соответствующие вопросы:

Ответы [ 2 ]

0 голосов
/ 29 января 2019

Простой способ состоит в том, чтобы сделать вашу таблицу стилей «белым списком»:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="group">
    <xsl:copy>
        <xsl:apply-templates select="node1 | node2"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="node1">
    <xsl:copy>
        <xsl:apply-templates select="@attr1"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="node2">
    <xsl:copy>
        <xsl:apply-templates select="@attr5 | @attr6"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

В противном случае это может быть довольно сложно:

  • Относительно легко проверить, появляется ли узел в указанном белом списке под его именем (как они поступают с другими вопросами, с которыми вы связаны);

  • Это не так просто - особенно.в XSLT 1.0 - чтобы увидеть, появляется ли узел в той же позиции в иерархии дерева (то есть, что путь к нему совпадает с путем к узлу в белом списке).

Если достаточно проверить только по имени, вы можете сделать что-то вроде:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="http://example.com/my"
exclude-result-prefixes="my">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<my:whitelist>
    <root>
        <header/>
        <group>
            <node1 attr1=""/>
            <node2 attr5="" attr6=""/>
        </group>
    </root>
</my:whitelist>

<xsl:variable name="whitelist" select="document('')/xsl:stylesheet/my:whitelist"/>

<xsl:template match="*">
    <xsl:if test="$whitelist//*[name() = name(current())]">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:if>
</xsl:template>

<xsl:template match="@*">
    <xsl:if test="$whitelist//@*[name() = name(current())]">
        <xsl:copy/>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

Но тогда, конечно, вы могли бы упростить структуру белого списка, поскольку он полностью игнорируется.


Для примера того, как это можно сделать с белым списком, состоящим из путей см .: https://stackoverflow.com/a/30276667/3016153

0 голосов
/ 29 января 2019

Будет ли это сделать для вас?Имейте единственный шаблон, который соответствует дочерним элементам group элементов, и затем проверьте документ белого списка, чтобы видеть, копировать ли этот узел, и если да, то какие атрибуты также должны быть скопированы

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns="ns" version="1.0">
    <xsl:output method="xml" encoding="UTF-8" indent="yes" />

    <ns:WhiteList>
        <node>
            <name>node1</name>
            <attr>attr1</attr>
        </node>
        <node>
            <name>node2</name>
            <attr>attr5</attr>
            <attr>attr6</attr>
        </node>
    </ns:WhiteList>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="group/*">
        <xsl:variable name="node" select="document('')//ns:WhiteList/node[name = name(current())]" />
        <xsl:if test="$node">
            <xsl:copy>
                <xsl:apply-templates select="@*[name() = $node/attr]|node()" />
            </xsl:copy>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>
...