2015-11-26 2 views
1

Мне нужно выбрать все <next> узлов, но за исключением <element4> от каждого и добавить новый элемент на свое место (это будет замена). Я работаю с php.XPath выбор исключая элемент из дочернего узла

<root> 
<next> 
    <node> 
    <element1>text</element1> 
    <element2>text</element1> 
    <element3>text</element1> 
    <element4>text</element1> 
    </node> 
    <node> 
    <element1>text</element1> 
    <element2>text</element1> 
    <element3>text</element1> 
    <element4>text</element1> 
    </node> 
</next> 
</root> 

поэтому он должен выглядеть следующим образом:

<next> 
    <node> 
    <element1>text</element1> 
    <element2>text</element1> 
    <element3>text</element1> 
    <new>text</new> 
    </node> 
    <node> 
    <element1>text</element1> 
    <element2>text</element1> 
    <element3>text</element1> 
    <new><int xmlns="foo.bar">0</int></new> 
    </node> 
</next> 

Любые советы? Спасибо!

+0

Не знаю, почему он не изменил элемент первого , но оба элементы должны как то же самое с 0

+0

AFAIK, это невозможно используя только XPath. – Kachna

+0

Качна, ты знаешь какой-нибудь другой способ сделать это? –

ответ

1

XPath - это язык выбора: он выбирает узлы или атомарные элементы из последовательности ввода, это язык выбора, чтобы сделать выбор по XML или иерархическим данным, поскольку SQL (обычно) является языком выбора с реляционными базами данных ,

Таким образом, вы можете исключить элементов выбора, но вы не можете обновления или изменения исходной последовательность. Можно сделать ограниченное преобразование (т. Е. Превратить строку в целое число), но это изменит выбранное значение, оно не изменит источник. Хотя XPath (а именно версия 2.0 и выше) может «создавать» атомные значения «на лету», он не может создавать новые элементы.

Это возможно и будет возвращать числовые значения в XPath 2.0:

/next/node/number(.) 

Но это невозможно:

/next/node/(if (element4) then create-element(.) else .) 

Однако в XSLT 2.0 и выше вы можете создать функцию, которая создает элементы. Как было сказано выше, XPath выбирает, и если вы хотите изменить документ, вы можете создать новый документ с использованием XSLT (значение T для Transformation).

Что-то вроде следующего (частично XSLT 2.0, вам нужно добавить заголовки):

<xsl:function name="f:create"> 
    <xsl:param name="node" /> 
    <xsl:param name="name" /> 
    <xsl:choose> 
     <xsl:when test="name($node) = $name"> 
      <xsl:element name="{if(number($node)) then 'int' else 'new'}"> 
       <xsl:value-of select="$node" /> 
      </xsl:element> 
     </xsl:when> 
     <xsl:otherwise><xsl:copy-of select="$node" /></xsl:otherwise> 
    </xsl:choose> 
</xsl:function> 

<xsl:template match="node"> 
    <!-- now XPath, with help of XSLT function, can conditionally create nodes --> 
    <xsl:copy-of select="child::*/create(., 'element4')" /> 
</xsl:template> 

<!-- boilerplate code, typically used to recursively copy non-matched nodes --> 
<xsl:template match="node() | @*"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()" /> 
    </xsl:copy> 
</xsl:template> 

Обратите внимание, что, в то время как это показывает, как вы можете создать другой элемент, используя XPath и функцию XSLT, это не меняет источник, он изменяет выход. Кроме того, это не рекомендуется, так как в XSLT такая же картина более легко сделать, просто выполнив:

<!-- the more specific match --> 
<xsl:template match="element4[number(.)]"> 
    <new> 
     <int xmlns="foo.bar"> 
      <xsl:value-of select="number(.)" /> 
     </int> 
    </new> 
<xsl:template> 

<!-- XSLT will automatically fallback to this one if the former fails --> 
<xsl:template match="element4"> 
    <new><xsl:copy-of select="node()" /></new> 
</xsl:template> 

<!-- or this one, if both the former fail --> 
<xsl:template match="node() | @*"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()" /> 
    </xsl:copy> 
</xsl:template> 
+0

Спасибо Абель. Я должен буду прочитать о XSLT, чтобы понять, что вы сделали. Еще раз спасибо! –