Sdílet prostřednictvím


Konstrukce XML (XQuery)

platí pro:SQL Server

V XQuery můžete pomocí přímých a počítaných konstruktorů vytvářet struktury XML v rámci dotazu.

Poznámka:

Mezi přímým a vypočítaným konstruktory není žádný rozdíl.

Použití přímých konstruktorů

Při použití přímých konstruktorů zadáte syntaxi typu XML při vytváření XML. Následující příklady ilustrují výstavbu XML přímými konstruktory.

Konstrukce elementů

Při použití zápisů XML můžete vytvořit elementy. Následující příklad používá výraz konstruktoru přímého elementu <ProductModel> a vytvoří prvek. Vytvořený prvek má tři podřízené prvky.

  • Textový uzel.

  • Dva uzly <Summary> prvků a <Features>.

    • Prvek <Summary> má jeden podřízený textový uzel, jehož hodnota je "Some description".

    • Prvek <Features> má tři podřízené prvky uzlu, <Color><Weight>, a <Warranty>. Každý z těchto uzlů má jeden podřízený textový uzel a má hodnoty Red, 25, 2 years parts and laborv uvedeném pořadí.

DECLARE @x AS XML;

SET @x = '';

SELECT @x.query('<ProductModel ProductModelID="111">;
This is product model catalog description.
<Summary>Some description</Summary>
<Features>
  <Color>Red</Color>
  <Weight>25</Weight>
  <Warranty>2 years parts and labor</Warranty>
</Features></ProductModel>');

Tady je výsledný kód XML:

<ProductModel ProductModelID="111">
  This is product model catalog description.
  <Summary>Some description</Summary>
  <Features>
    <Color>Red</Color>
    <Weight>25</Weight>
    <Warranty>2 years parts and labor</Warranty>
  </Features>
</ProductModel>

I když vytváření prvků z konstantních výrazů, jak je znázorněno v tomto příkladu, je užitečné, skutečný výkon této funkce jazyka XQuery je schopnost vytvořit XML, který dynamicky extrahuje data z databáze. Složené závorky můžete použít k zadání výrazů dotazu. Ve výsledném jazyce XML se výraz nahradí jeho hodnotou. Například následující dotaz vytvoří prvek s jedním podřízeným <NewRoot> elementem (<e>). Hodnota elementu <e> se vypočítá zadáním výrazu cesty uvnitř složených závorek ("{ ... }").

DECLARE @x AS XML;

SET @x = '<root>5</root>';

SELECT @x.query('<NewRoot><e> { /root } </e></NewRoot>');

Složené závorky fungují jako tokeny přepínání kontextu a přepínají dotaz z konstrukce XML na vyhodnocení dotazu. V tomto případě je výraz cesty XQuery uvnitř závorek /rootvyhodnocen a výsledky jsou nahrazeny.

Tady je výsledek:

<NewRoot>
  <e>
    <root>5</root>
  </e>
</NewRoot>

Následující dotaz je podobný předchozímu dotazu. Výraz ve složených závorkách však určuje data() funkci, která načte atomickou hodnotu <root> elementu a přiřadí ho k vytvořenému prvku. <e>

DECLARE @x AS XML;
SET @x = '<root>5</root>';

DECLARE @y AS XML;
SET @y = (SELECT @x.query('
                           <NewRoot>
                             <e> { data(/root) } </e>
                           </NewRoot>'));

SELECT @y;

Tady je výsledek:

<NewRoot>
  <e>5</e>
</NewRoot>

Pokud chcete použít složené závorky jako součást textu místo tokenů pro přepínání kontextu, můžete je označit jako }} nebo {{{, jak je znázorněno v tomto příkladu:

DECLARE @x AS XML;
SET @x = '<root>5</root>';

DECLARE @y AS XML;
SET @y = (SELECT @x.query('
<NewRoot> Hello, I can use {{ and  }} as part of my text</NewRoot>'));

SELECT @y;

Tady je výsledek:

<NewRoot> Hello, I can use { and  } as part of my text</NewRoot>

Následující dotaz je dalším příkladem vytváření prvků pomocí konstruktoru přímého elementu. Také hodnota <FirstLocation> prvku je získána spuštěním výrazu ve složených závorkách. Výraz dotazu vrátí výrobní kroky v prvním umístění pracovního centra ze sloupce Pokyny v tabulce Production.ProductModel.

SELECT Instructions.query('
    declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
        <FirstLocation>
           { /AWMI:root/AWMI:Location[1]/AWMI:step }
        </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Tady je výsledek:

<FirstLocation>
  <AWMI:step xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions">
      Insert <AWMI:material>aluminum sheet MS-2341</AWMI:material> into the <AWMI:tool>T-85A framing tool</AWMI:tool>.
  </AWMI:step>
  <AWMI:step xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions">
      Attach <AWMI:tool>Trim Jig TJ-26</AWMI:tool> to the upper and lower right corners of the aluminum sheet.
  </AWMI:step>
   ...
</FirstLocation>

Obsah elementů ve konstrukci XML

Následující příklad znázorňuje chování výrazů při vytváření obsahu elementu pomocí konstruktoru přímého elementu. V následujícím příkladu konstruktor přímého elementu určuje jeden výraz. Pro tento výraz se ve výsledném XML vytvoří jeden textový uzel.

DECLARE @x AS XML;
SET @x = '
<root>
  <step>This is step 1</step>
  <step>This is step 2</step>
  <step>This is step 3</step>
</root>';

SELECT @x.query('
<result>
 { for $i in /root[1]/step
    return string($i)
 }
</result>');

Sekvence atomických hodnot vyplývající z vyhodnocení výrazu se přidá do textového uzlu s mezerou přidanou mezi sousední atomické hodnoty, jak je znázorněno ve výsledku. Vytvořený prvek má jeden podřízený prvek. Jedná se o textový uzel, který obsahuje hodnotu zobrazenou ve výsledku.

<result>This is step 1 This is step 2 This is step 3</result>

Pokud místo jednoho výrazu zadáte tři samostatné výrazy, které generují tři textové uzly, sloučí se sousední textové uzly do jednoho textového uzlu zřetězením ve výsledném XML.

DECLARE @x AS XML;
SET @x = '
<root>
  <step>This is step 1</step>
  <step>This is step 2</step>
  <step>This is step 3</step>
</root>';

SELECT @x.query('
<result>
 { string(/root[1]/step[1]) }
 { string(/root[1]/step[2]) }
 { string(/root[1]/step[3]) }
</result>');

Vytvořený uzel elementu má jednu podřízenou. Jedná se o textový uzel, který obsahuje hodnotu zobrazenou ve výsledku.

<result>This is step 1This is step 2This is step 3</result>

Vytváření atributů

Při vytváření elementů pomocí konstruktoru přímých elementů můžete také určit atributy elementu pomocí syntaxe podobné xml, jak je znázorněno v tomto příkladu:

DECLARE @x AS XML;
SET @x = '';

SELECT @x.query('<ProductModel ProductModelID="111">;
This is product model catalog description.
<Summary>Some description</Summary>
</ProductModel>');

Tady je výsledný kód XML:

<ProductModel ProductModelID="111">
  This is product model catalog description.
  <Summary>Some description</Summary>
</ProductModel>

Vytvořený element <ProductModel> má atribut ProductModelID a tyto podřízené uzly:

  • Textový uzel This is product model catalog description.

  • Uzel elementu . <Summary> Tento uzel má jeden podřízený textový uzel. Some description

Při vytváření atributu můžete zadat jeho hodnotu pomocí výrazu ve složených závorkách. V tomto případě se výsledek výrazu vrátí jako hodnota atributu.

V následujícím příkladu data() není funkce striktně povinná. Vzhledem k tomu, že přiřazujete hodnotu výrazu atributu, data() implicitně se použije k načtení typové hodnoty zadaného výrazu.

DECLARE @x AS XML;
SET @x = '<root>5</root>';

DECLARE @y AS XML;
SET @y = (SELECT @x.query('<NewRoot attr="{ data(/root) }" ></NewRoot>'));

SELECT @y;

Tady je výsledek:

<NewRoot attr="5" />

Následuje další příklad, ve kterém jsou výrazy zadány pro locationID a SetupHrs vytváření atributů. Tyto výrazy se vyhodnocují proti xml ve sloupci Instrukce. Typovaná hodnota výrazu je přiřazena atributům.

SELECT Instructions.query('
    declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
        <FirstLocation
         LocationID="{ (/AWMI:root/AWMI:Location[1]/@LocationID)[1] }"
         SetupHrs = "{ (/AWMI:root/AWMI:Location[1]/@SetupHours)[1] }" >
           { /AWMI:root/AWMI:Location[1]/AWMI:step }
        </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Tady je částečný výsledek:

<FirstLocation LocationID="10" SetupHours="0.5" >
  <AWMI:step ...
  </AWMI:step>
  ...
</FirstLocation>

Omezení implementace

Toto jsou omezení:

  • Více nebo smíšených (řetězcových a výrazů výrazu XQuery) se nepodporuje. Například, jak je znázorněno v následujícím dotazu, vytvoříte XML, kde Item je konstanta a hodnota 5 se získá vyhodnocením výrazu dotazu:

    <a attr="Item 5" />
    

    Následující dotaz vrátí chybu, protože směšujete konstantní řetězec s výrazem ({/x}) a nepodporuje se to:

    DECLARE @x AS XML;
    SET @x = '<x>5</x>';
    
    SELECT @x.query('<a attr="Item {/x}"/>');
    

    V tomto případě máte následující možnosti:

    • Vytvořte hodnotu atributu zřetězením dvou atomických hodnot. Tyto atomické hodnoty jsou serializovány do hodnoty atributu s mezerou mezi atomovými hodnotami:

      SELECT @x.query('<a attr="{''Item'', data(/x)}"/>');
      

      Tady je výsledek:

      <a attr="Item 5" />
      
    • Funkci concat použijte ke zřetězení dvou řetězcových argumentů do výsledné hodnoty atributu:

      SELECT @x.query('<a attr="{concat(''Item'', /x[1])}"/>');
      

      V tomto případě není mezi těmito dvěma řetězcovými hodnotami přidáno žádné místo. Pokud chcete mezeru mezi těmito dvěma hodnotami, musíte ji explicitně zadat.

      Tady je výsledek:

      <a attr="Item5" />
      
  • Více výrazů jako hodnota atributu se nepodporuje. Například následující dotaz vrátí chybu:

    DECLARE @x AS XML;
    SET @x = '<x>5</x>';
    
    SELECT @x.query('<a attr="{/x}{/x}"/>');
    
  • Heterogenní sekvence nejsou podporovány. Jakýkoli pokus o přiřazení heterogenní sekvence jako hodnota atributu vrátí chybu, jak je znázorněno v následujícím příkladu. V tomto příkladu je heterogenní sekvence, řetězec Item a element <x>, je zadán jako hodnota atributu:

    DECLARE @x AS XML;
    SET @x = '<x>5</x>';
    
    SELECT @x.query('<a attr="{''Item'', /x }" />');
    

    Pokud použijete data() funkci, dotaz funguje, protože načte atomovou hodnotu výrazu, /xkterá je zřetězena s řetězcem. Následuje posloupnost atomických hodnot:

    SELECT @x.query('<a attr="{''Item'', data(/x)}"/>');
    

    Tady je výsledek:

    <a attr="Item 5" />
    
  • Pořadí uzlů atributů se vynucuje při serializaci, nikoli při kontrole statického typu. Například následující dotaz selže, protože se pokusí přidat atribut za uzel bez atributu.

    SELECT CONVERT (XML, '').query('
        element x { attribute att { "pass" }, element y { "Element text" }, attribute att2 { "fail" } }
        ');
    GO
    

    Předchozí dotaz vrátí následující chybu:

    XML well-formedness check: Attribute cannot appear outside of element declaration. Rewrite your XQuery so it returns well-formed XML.
    

Přidání oborů názvů

Při vytváření XML pomocí přímých konstruktorů lze konstruovaný prvek a názvy atributů kvalifikovat pomocí předpony oboru názvů. Předponu k oboru názvů můžete svázat následujícími způsoby:

  • Pomocí atributu deklarace oboru názvů.
  • WITH XMLNAMESPACES Pomocí klauzule.
  • V prologu XQuery.

Přidání oborů názvů pomocí atributu deklarace oboru názvů

Následující příklad používá atribut deklarace oboru názvů při konstrukci elementu <a> deklarovat výchozí obor názvů. Konstrukce podřízeného elementu <b> vrátí deklaraci výchozího oboru názvů deklarovaného v nadřazený prvek.

DECLARE @x AS XML;
SET @x = '<x>5</x>';

SELECT @x.query('
  <a xmlns="a">
    <b xmlns=""/>
  </a>');

Tady je výsledek:

<a xmlns="a">
  <b xmlns="" />
</a>

K oboru názvů můžete přiřadit předponu. Předpona je určena při konstrukci prvku <a>.

DECLARE @x AS XML;
SET @x = '<x>5</x>';

SELECT @x.query('
  <x:a xmlns:x="a">
    <b/>
  </x:a>');

Tady je výsledek:

<x:a xmlns:x="a">
  <b />
</x:a>

Ve konstrukci XML můžete zrušit deklaraci výchozího oboru názvů, ale nemůžete zrušit deklaraci předpony oboru názvů. Následující dotaz vrátí chybu, protože nelze zrušit deklaraci předpony, jak je uvedeno ve konstrukci prvku <b>.

DECLARE @x AS XML;
SET @x = '<x>5</x>';

SELECT @x.query('
  <x:a xmlns:x="a">
    <b xmlns:x=""/>
  </x:a>');

Nově vytvořený obor názvů je k dispozici pro použití uvnitř dotazu. Například následující dotaz deklaruje obor názvů při vytváření elementu <FirstLocation>a určuje předponu ve výrazech pro hodnoty atributu LocationID a SetupHrs.

SELECT Instructions.query('
        <FirstLocation xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"
         LocationID="{ (/AWMI:root/AWMI:Location[1]/@LocationID)[1] }"
         SetupHrs = "{ (/AWMI:root/AWMI:Location[1]/@SetupHours)[1] }" >
           { /AWMI:root/AWMI:Location[1]/AWMI:step }
        </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Vytvoření nové předpony oboru názvů tímto způsobem přepíše všechny existující deklarace oboru názvů pro tuto předponu. Například deklarace oboru názvů , AWMI="https://someURI"v dotazu prolog je přepsána deklarací oboru názvů v elementu <FirstLocation> .

SELECT Instructions.query('
declare namespace AWMI="https://someURI";
        <FirstLocation xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"
         LocationID="{ (/AWMI:root/AWMI:Location[1]/@LocationID)[1] }"
         SetupHrs = "{ (/AWMI:root/AWMI:Location[1]/@SetupHours)[1] }" >
           { /AWMI:root/AWMI:Location[1]/AWMI:step }
        </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Přidání oborů názvů pomocí prologu

Tento příklad ukazuje, jak lze obory názvů přidat do vytvořeného XML. Výchozí obor názvů je deklarován v prologu dotazu.

DECLARE @x AS XML;
SET @x = '<x>5</x>';

SELECT @x.query('
           declare default element namespace "a";
            <a><b xmlns=""/></a>');

Ve konstrukci elementu <b>je atribut deklarace oboru názvů zadán s prázdným řetězcem jako jeho hodnotou. Toto zrušení deklaruje výchozí obor názvů, který je deklarován v nadřazené objektu.

Tady je výsledek:

<a xmlns="a">
  <b xmlns="" />
</a>

Zpracování konstrukce XML a prázdného místa

Obsah elementu ve konstrukci XML může obsahovat prázdné znaky. Tyto znaky se zpracovávají následujícími způsoby:

  • Prázdné znaky v identifikátorech URI oboru názvů jsou považovány za typ anyURIXSD . Konkrétně se jedná o způsob jejich zpracování:

    • Všechny prázdné znaky na začátku a konci se oříznou.
    • Vnitřní prázdné hodnoty znaků jsou sbalené do jediného místa.
  • Znaky řádku uvnitř obsahu atributu jsou nahrazeny mezerami. Všechny ostatní prázdné znaky zůstanou tak, jak jsou.

  • Prázdné znaky uvnitř prvků se zachovají.

Následující příklad znázorňuje zpracování prázdných znaků ve konstrukci XML:

-- line feed is replaced by space.
DECLARE @x AS XML;
SET @x = '';

SELECT @x.query('

declare namespace myNS="   https://
 abc/
xyz

";
<test attr="    my
test   attr
value    " >

<a>

This     is  a

test

</a>
</test>
') AS XML_Result;

Tady je výsledek:

-- result
<test attr="<test attr="    my test   attr  value    "><a>

This     is  a

test

</a></test>
"><a>

This     is  a

test

</a></test>

Další přímé konstruktory XML

Konstruktory pro zpracování instrukcí a komentářů XML používají stejnou syntaxi jako odpovídající syntaxe konstruktoru XML. Podporované jsou také počítané konstruktory pro textové uzly, ale primárně se používají XML DML k vytváření textových uzlů.

Poznámka:

Příklad použití explicitního konstruktoru textového uzlu najdete v konkrétním příkladu vložení (XML DML).

V následujícím dotazu obsahuje vytvořený KÓD XML prvek, dva atributy, komentář a instrukce pro zpracování. Před objektem <FirstLocation>se používá čárka, protože se konstruuje posloupnost.

SELECT Instructions.query('
  declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
   <?myProcessingInstr abc="value" ?>,
   <FirstLocation
        WorkCtrID = "{ (/AWMI:root/AWMI:Location[1]/@LocationID)[1] }"
        SetupHrs = "{ (/AWMI:root/AWMI:Location[1]/@SetupHours)[1] }" >
       <!-- some comment -->
       <?myPI some processing instructions ?>
       { (/AWMI:root/AWMI:Location[1]/AWMI:step) }
    </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Tady je částečný výsledek:

<?myProcessingInstr abc="value" ?>
<FirstLocation WorkCtrID="10" SetupHrs="0.5">
  <!-- some comment -->
  <?myPI some processing instructions ?>
  <AWMI:step xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions">I
  nsert <AWMI:material>aluminum sheet MS-2341</AWMI:material> into the <AWMI:tool>T-85A framing tool</AWMI:tool>.
  </AWMI:step>
    ...
</FirstLocation>

Použití počítaných konstruktorů

V tomto případě zadáte klíčová slova, která identifikují typ uzlu, který chcete sestavit. Podporují se pouze následující klíčová slova:

  • element
  • atribut
  • poslat SMS

U uzlů elementů a atributů jsou tato klíčová slova následovaná názvem uzlu a také výrazem uzavřeným ve složených závorkách, která generuje obsah tohoto uzlu. V následujícím příkladu vytváříte tento KÓD XML:

<root>
  <ProductModel PID="5">Some text <summary>Some Summary</summary></ProductModel>
</root>

Tady je dotaz, který používá počítané konstruktory, vygeneruje XML:

DECLARE @x AS XML;
SET @x = '';

SELECT @x.query('element root
               {
                  element ProductModel
     {
attribute PID { 5 },
text{"Some text "},
    element summary { "Some Summary" }
 }
               } ');

Výraz, který generuje obsah uzlu, může zadat výraz dotazu.

DECLARE @x AS XML;
SET @x = '<a attr="5"><b>some summary</b></a>';

SELECT @x.query('element root
               {
                  element ProductModel
     {
attribute PID { /a/@attr },
text{"Some text "},
    element summary { /a/b }
 }
               } ');

Počítaný element a konstruktory atributů, jak je definováno ve specifikaci XQuery, umožňují vypočítat názvy uzlů. Při použití přímých konstruktorů v SQL Serveru musí být názvy uzlů, například element a atribut, zadány jako konstantní literály. Proto není v přímých konstruktorech a počítaných konstruktorech pro prvky a atributy žádný rozdíl.

V následujícím příkladu se obsah vytvořených uzlů získá z pokynů pro výrobu XML uložených ve sloupci Pokyny xml datového typu v tabulce ProductModel.

SELECT Instructions.query('
  declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
   element FirstLocation
     {
        attribute LocationID { (/AWMI:root/AWMI:Location[1]/@LocationID)[1] },
        element   AllTheSteps { /AWMI:root/AWMI:Location[1]/AWMI:step }
     }
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

Tady je částečný výsledek:

<FirstLocation LocationID="10">
  <AllTheSteps>
    <AWMI:step> ... </AWMI:step>
    <AWMI:step> ... </AWMI:step>
    ...
  </AllTheSteps>
</FirstLocation>

Další omezení implementace

Konstruktory vypočítaných atributů nelze použít k deklaraci nového oboru názvů. Sql Server také nepodporuje následující počítané konstruktory:

  • Konstruktory uzlu vypočítaného dokumentu
  • Konstruktory instrukcí vypočítaného zpracování
  • Konstruktory počítaných komentářů