diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs | 252 |
1 files changed, 119 insertions, 133 deletions
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs index 9054569..dd4095d 100644 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs +++ b/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs | |||
@@ -121,7 +121,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
121 | /// This property is declared locally because it is used a lot and | 121 | /// This property is declared locally because it is used a lot and |
122 | /// brevity is nice. | 122 | /// brevity is nice. |
123 | /// </summary> | 123 | /// </summary> |
124 | |||
125 | internal string MsgId | 124 | internal string MsgId |
126 | { | 125 | { |
127 | get { return Rest.MsgId; } | 126 | get { return Rest.MsgId; } |
@@ -139,7 +138,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
139 | /// <param name=response>Outbound HTTP request information</param> | 138 | /// <param name=response>Outbound HTTP request information</param> |
140 | /// <param name=qPrefix>REST service domain prefix</param> | 139 | /// <param name=qPrefix>REST service domain prefix</param> |
141 | /// <returns>A RequestData instance suitable for this service</returns> | 140 | /// <returns>A RequestData instance suitable for this service</returns> |
142 | |||
143 | private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) | 141 | private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) |
144 | { | 142 | { |
145 | return (RequestData) new InventoryRequestData(request, response, prefix); | 143 | return (RequestData) new InventoryRequestData(request, response, prefix); |
@@ -152,7 +150,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
152 | /// It handles all aspects of inventory REST processing, i.e. /admin/inventory | 150 | /// It handles all aspects of inventory REST processing, i.e. /admin/inventory |
153 | /// </summary> | 151 | /// </summary> |
154 | /// <param name=hdata>A consolidated HTTP request work area</param> | 152 | /// <param name=hdata>A consolidated HTTP request work area</param> |
155 | |||
156 | private void DoInventory(RequestData hdata) | 153 | private void DoInventory(RequestData hdata) |
157 | { | 154 | { |
158 | InventoryRequestData rdata = (InventoryRequestData) hdata; | 155 | InventoryRequestData rdata = (InventoryRequestData) hdata; |
@@ -295,7 +292,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
295 | Rest.Log.DebugFormat("{0} Inventory catalog requested for {1} {2}", | 292 | Rest.Log.DebugFormat("{0} Inventory catalog requested for {1} {2}", |
296 | MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); | 293 | MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); |
297 | 294 | ||
298 | |||
299 | lock (rdata) | 295 | lock (rdata) |
300 | { | 296 | { |
301 | if (!rdata.HaveInventory) | 297 | if (!rdata.HaveInventory) |
@@ -373,7 +369,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
373 | /// corresponding subtree based upon node name. | 369 | /// corresponding subtree based upon node name. |
374 | /// </summary> | 370 | /// </summary> |
375 | /// <param name=rdata>HTTP service request work area</param> | 371 | /// <param name=rdata>HTTP service request work area</param> |
376 | |||
377 | private void DoGet(InventoryRequestData rdata) | 372 | private void DoGet(InventoryRequestData rdata) |
378 | { | 373 | { |
379 | rdata.initXmlWriter(); | 374 | rdata.initXmlWriter(); |
@@ -439,7 +434,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
439 | /// context identified by the URI. | 434 | /// context identified by the URI. |
440 | /// </summary> | 435 | /// </summary> |
441 | /// <param name=rdata>HTTP service request work area</param> | 436 | /// <param name=rdata>HTTP service request work area</param> |
442 | |||
443 | private void DoExtend(InventoryRequestData rdata) | 437 | private void DoExtend(InventoryRequestData rdata) |
444 | { | 438 | { |
445 | bool created = false; | 439 | bool created = false; |
@@ -480,7 +474,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
480 | // [3] A (possibly empty) set of assets. | 474 | // [3] A (possibly empty) set of assets. |
481 | // If all of these are empty, then the POST is a harmless no-operation. | 475 | // If all of these are empty, then the POST is a harmless no-operation. |
482 | 476 | ||
483 | XmlInventoryCollection entity = ReconstituteEntity(rdata); | 477 | XmlInventoryCollection entity = ReconstituteEntity(rdata); |
484 | 478 | ||
485 | // Inlined assets can be included in entity. These must be incorporated into | 479 | // Inlined assets can be included in entity. These must be incorporated into |
486 | // the asset database before we attempt to update the inventory. If anything | 480 | // the asset database before we attempt to update the inventory. If anything |
@@ -667,7 +661,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
667 | /// during the reconstitution process. | 661 | /// during the reconstitution process. |
668 | /// </summary> | 662 | /// </summary> |
669 | /// <param name=rdata>HTTP service request work area</param> | 663 | /// <param name=rdata>HTTP service request work area</param> |
670 | |||
671 | private void DoUpdate(InventoryRequestData rdata) | 664 | private void DoUpdate(InventoryRequestData rdata) |
672 | { | 665 | { |
673 | int count = 0; | 666 | int count = 0; |
@@ -1303,7 +1296,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
1303 | /// <param name=rdata>HTTP service request work area</param> | 1296 | /// <param name=rdata>HTTP service request work area</param> |
1304 | /// <param name=i>The item to be formatted</param> | 1297 | /// <param name=i>The item to be formatted</param> |
1305 | /// <param name=indent>Pretty print indentation</param> | 1298 | /// <param name=indent>Pretty print indentation</param> |
1306 | |||
1307 | private void formatItem(InventoryRequestData rdata, InventoryItemBase i, string indent) | 1299 | private void formatItem(InventoryRequestData rdata, InventoryItemBase i, string indent) |
1308 | { | 1300 | { |
1309 | Rest.Log.DebugFormat("{0} Item : {1} {2} {3} Type = {4}, AssetType = {5}", | 1301 | Rest.Log.DebugFormat("{0} Item : {1} {2} {3} Type = {4}, AssetType = {5}", |
@@ -1349,7 +1341,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
1349 | /// that required it cannot be completed, and it fails accordingly. | 1341 | /// that required it cannot be completed, and it fails accordingly. |
1350 | /// </summary> | 1342 | /// </summary> |
1351 | /// <param name=rdata>HTTP service request work area</param> | 1343 | /// <param name=rdata>HTTP service request work area</param> |
1352 | |||
1353 | private InventoryFolderBase GetTrashCan(InventoryRequestData rdata) | 1344 | private InventoryFolderBase GetTrashCan(InventoryRequestData rdata) |
1354 | { | 1345 | { |
1355 | InventoryFolderBase TrashCan = null; | 1346 | InventoryFolderBase TrashCan = null; |
@@ -1394,7 +1385,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
1394 | /// </summary> | 1385 | /// </summary> |
1395 | /// <param name=newf>Folder obtained from enclosed entity</param> | 1386 | /// <param name=newf>Folder obtained from enclosed entity</param> |
1396 | /// <param name=oldf>Folder obtained from the user's inventory</param> | 1387 | /// <param name=oldf>Folder obtained from the user's inventory</param> |
1397 | |||
1398 | private bool FolderHasChanged(InventoryFolderBase newf, InventoryFolderBase oldf) | 1388 | private bool FolderHasChanged(InventoryFolderBase newf, InventoryFolderBase oldf) |
1399 | { | 1389 | { |
1400 | return (newf.Name != oldf.Name | 1390 | return (newf.Name != oldf.Name |
@@ -1411,7 +1401,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
1411 | /// </summary> | 1401 | /// </summary> |
1412 | /// <param name=newf>Item obtained from enclosed entity</param> | 1402 | /// <param name=newf>Item obtained from enclosed entity</param> |
1413 | /// <param name=oldf>Item obtained from the user's inventory</param> | 1403 | /// <param name=oldf>Item obtained from the user's inventory</param> |
1414 | |||
1415 | private bool ItemHasChanged(InventoryItemBase newf, InventoryItemBase oldf) | 1404 | private bool ItemHasChanged(InventoryItemBase newf, InventoryItemBase oldf) |
1416 | { | 1405 | { |
1417 | return (newf.Name != oldf.Name | 1406 | return (newf.Name != oldf.Name |
@@ -1449,7 +1438,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
1449 | /// missing parent IDs are resolved). | 1438 | /// missing parent IDs are resolved). |
1450 | /// </summary> | 1439 | /// </summary> |
1451 | /// <param name=rdata>HTTP service request work area</param> | 1440 | /// <param name=rdata>HTTP service request work area</param> |
1452 | |||
1453 | internal XmlInventoryCollection ReconstituteEntity(InventoryRequestData rdata) | 1441 | internal XmlInventoryCollection ReconstituteEntity(InventoryRequestData rdata) |
1454 | { | 1442 | { |
1455 | Rest.Log.DebugFormat("{0} Reconstituting entity", MsgId); | 1443 | Rest.Log.DebugFormat("{0} Reconstituting entity", MsgId); |
@@ -1468,78 +1456,80 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
1468 | { | 1456 | { |
1469 | switch (ic.xml.NodeType) | 1457 | switch (ic.xml.NodeType) |
1470 | { | 1458 | { |
1471 | case XmlNodeType.Element : | 1459 | case XmlNodeType.Element : |
1472 | Rest.Log.DebugFormat("{0} StartElement: <{1}>", | 1460 | Rest.Log.DebugFormat("{0} StartElement: <{1}>", |
1473 | MsgId, ic.xml.Name); | ||
1474 | switch (ic.xml.Name) | ||
1475 | { | ||
1476 | case "Folder" : | ||
1477 | Rest.Log.DebugFormat("{0} Processing {1} element", | ||
1478 | MsgId, ic.xml.Name); | 1461 | MsgId, ic.xml.Name); |
1479 | CollectFolder(ic); | 1462 | switch (ic.xml.Name) |
1463 | { | ||
1464 | case "Folder" : | ||
1465 | Rest.Log.DebugFormat("{0} Processing {1} element", | ||
1466 | MsgId, ic.xml.Name); | ||
1467 | CollectFolder(ic); | ||
1468 | break; | ||
1469 | case "Item" : | ||
1470 | Rest.Log.DebugFormat("{0} Processing {1} element", | ||
1471 | MsgId, ic.xml.Name); | ||
1472 | CollectItem(ic); | ||
1473 | break; | ||
1474 | case "Asset" : | ||
1475 | Rest.Log.DebugFormat("{0} Processing {1} element", | ||
1476 | MsgId, ic.xml.Name); | ||
1477 | CollectAsset(ic); | ||
1478 | break; | ||
1479 | case "Permissions" : | ||
1480 | Rest.Log.DebugFormat("{0} Processing {1} element", | ||
1481 | MsgId, ic.xml.Name); | ||
1482 | CollectPermissions(ic); | ||
1483 | break; | ||
1484 | default : | ||
1485 | Rest.Log.DebugFormat("{0} Ignoring {1} element", | ||
1486 | MsgId, ic.xml.Name); | ||
1487 | break; | ||
1488 | } | ||
1489 | // This stinks, but the ReadElement call above not only reads | ||
1490 | // the imbedded data, but also consumes the end tag for Asset | ||
1491 | // and moves the element pointer on to the containing Item's | ||
1492 | // element-end, however, if there was a permissions element | ||
1493 | // following, it would get us to the start of that.. | ||
1494 | if (ic.xml.NodeType == XmlNodeType.EndElement && | ||
1495 | ic.xml.Name == "Item") | ||
1496 | { | ||
1497 | Validate(ic); | ||
1498 | } | ||
1480 | break; | 1499 | break; |
1481 | case "Item" : | 1500 | |
1482 | Rest.Log.DebugFormat("{0} Processing {1} element", | 1501 | case XmlNodeType.EndElement : |
1483 | MsgId, ic.xml.Name); | 1502 | switch (ic.xml.Name) |
1484 | CollectItem(ic); | 1503 | { |
1485 | break; | 1504 | case "Folder" : |
1486 | case "Asset" : | 1505 | Rest.Log.DebugFormat("{0} Completing {1} element", |
1487 | Rest.Log.DebugFormat("{0} Processing {1} element", | 1506 | MsgId, ic.xml.Name); |
1488 | MsgId, ic.xml.Name); | 1507 | ic.Pop(); |
1489 | CollectAsset(ic); | 1508 | break; |
1490 | break; | 1509 | case "Item" : |
1491 | case "Permissions" : | 1510 | Rest.Log.DebugFormat("{0} Completing {1} element", |
1492 | Rest.Log.DebugFormat("{0} Processing {1} element", | 1511 | MsgId, ic.xml.Name); |
1493 | MsgId, ic.xml.Name); | 1512 | Validate(ic); |
1494 | CollectPermissions(ic); | 1513 | break; |
1514 | case "Asset" : | ||
1515 | Rest.Log.DebugFormat("{0} Completing {1} element", | ||
1516 | MsgId, ic.xml.Name); | ||
1517 | break; | ||
1518 | case "Permissions" : | ||
1519 | Rest.Log.DebugFormat("{0} Completing {1} element", | ||
1520 | MsgId, ic.xml.Name); | ||
1521 | break; | ||
1522 | default : | ||
1523 | Rest.Log.DebugFormat("{0} Ignoring {1} element", | ||
1524 | MsgId, ic.xml.Name); | ||
1525 | break; | ||
1526 | } | ||
1495 | break; | 1527 | break; |
1528 | |||
1496 | default : | 1529 | default : |
1497 | Rest.Log.DebugFormat("{0} Ignoring {1} element", | 1530 | Rest.Log.DebugFormat("{0} Ignoring: <{1}>:<{2}>", |
1498 | MsgId, ic.xml.Name); | 1531 | MsgId, ic.xml.NodeType, ic.xml.Value); |
1499 | break; | 1532 | break; |
1500 | } | ||
1501 | // This stinks, but the ReadElement call above not only reads | ||
1502 | // the imbedded data, but also consumes the end tag for Asset | ||
1503 | // and moves the element pointer on to the containing Item's | ||
1504 | // element-end, however, if there was a permissions element | ||
1505 | // following, it would get us to the start of that.. | ||
1506 | if (ic.xml.NodeType == XmlNodeType.EndElement && | ||
1507 | ic.xml.Name == "Item") | ||
1508 | { | ||
1509 | Validate(ic); | ||
1510 | } | ||
1511 | break; | ||
1512 | case XmlNodeType.EndElement : | ||
1513 | switch (ic.xml.Name) | ||
1514 | { | ||
1515 | case "Folder" : | ||
1516 | Rest.Log.DebugFormat("{0} Completing {1} element", | ||
1517 | MsgId, ic.xml.Name); | ||
1518 | ic.Pop(); | ||
1519 | break; | ||
1520 | case "Item" : | ||
1521 | Rest.Log.DebugFormat("{0} Completing {1} element", | ||
1522 | MsgId, ic.xml.Name); | ||
1523 | Validate(ic); | ||
1524 | break; | ||
1525 | case "Asset" : | ||
1526 | Rest.Log.DebugFormat("{0} Completing {1} element", | ||
1527 | MsgId, ic.xml.Name); | ||
1528 | break; | ||
1529 | case "Permissions" : | ||
1530 | Rest.Log.DebugFormat("{0} Completing {1} element", | ||
1531 | MsgId, ic.xml.Name); | ||
1532 | break; | ||
1533 | default : | ||
1534 | Rest.Log.DebugFormat("{0} Ignoring {1} element", | ||
1535 | MsgId, ic.xml.Name); | ||
1536 | break; | ||
1537 | } | ||
1538 | break; | ||
1539 | default : | ||
1540 | Rest.Log.DebugFormat("{0} [0] Ignoring: <{1}>:<2>", | ||
1541 | MsgId, ic.xml.NodeType, ic.xml.Value); | ||
1542 | break; | ||
1543 | } | 1533 | } |
1544 | } | 1534 | } |
1545 | } | 1535 | } |
@@ -1688,7 +1678,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
1688 | /// All context is reset whenever the effective folder changes | 1678 | /// All context is reset whenever the effective folder changes |
1689 | /// or an item is successfully validated. | 1679 | /// or an item is successfully validated. |
1690 | /// </summary> | 1680 | /// </summary> |
1691 | |||
1692 | private void CollectItem(XmlInventoryCollection ic) | 1681 | private void CollectItem(XmlInventoryCollection ic) |
1693 | { | 1682 | { |
1694 | Rest.Log.DebugFormat("{0} Interpret item element", MsgId); | 1683 | Rest.Log.DebugFormat("{0} Interpret item element", MsgId); |
@@ -1715,55 +1704,55 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
1715 | 1704 | ||
1716 | switch (ic.xml.Name) | 1705 | switch (ic.xml.Name) |
1717 | { | 1706 | { |
1718 | case "name" : | 1707 | case "name" : |
1719 | result.Name = ic.xml.Value; | 1708 | result.Name = ic.xml.Value; |
1720 | break; | 1709 | break; |
1721 | case "desc" : | 1710 | case "desc" : |
1722 | result.Description = ic.xml.Value; | 1711 | result.Description = ic.xml.Value; |
1723 | break; | 1712 | break; |
1724 | case "uuid" : | 1713 | case "uuid" : |
1725 | result.ID = new UUID(ic.xml.Value); | 1714 | result.ID = new UUID(ic.xml.Value); |
1726 | break; | 1715 | break; |
1727 | case "folder" : | 1716 | case "folder" : |
1728 | result.Folder = new UUID(ic.xml.Value); | 1717 | result.Folder = new UUID(ic.xml.Value); |
1729 | break; | 1718 | break; |
1730 | case "owner" : | 1719 | case "owner" : |
1731 | result.Owner = new UUID(ic.xml.Value); | 1720 | result.Owner = new UUID(ic.xml.Value); |
1732 | break; | 1721 | break; |
1733 | case "invtype" : | 1722 | case "invtype" : |
1734 | result.InvType = Int32.Parse(ic.xml.Value); | 1723 | result.InvType = Int32.Parse(ic.xml.Value); |
1735 | break; | 1724 | break; |
1736 | case "creator" : | 1725 | case "creator" : |
1737 | result.Creator = new UUID(ic.xml.Value); | 1726 | result.Creator = new UUID(ic.xml.Value); |
1738 | break; | 1727 | break; |
1739 | case "assettype" : | 1728 | case "assettype" : |
1740 | result.AssetType = Int32.Parse(ic.xml.Value); | 1729 | result.AssetType = Int32.Parse(ic.xml.Value); |
1741 | break; | 1730 | break; |
1742 | case "groupowned" : | 1731 | case "groupowned" : |
1743 | result.GroupOwned = Boolean.Parse(ic.xml.Value); | 1732 | result.GroupOwned = Boolean.Parse(ic.xml.Value); |
1744 | break; | 1733 | break; |
1745 | case "groupid" : | 1734 | case "groupid" : |
1746 | result.GroupID = new UUID(ic.xml.Value); | 1735 | result.GroupID = new UUID(ic.xml.Value); |
1747 | break; | 1736 | break; |
1748 | case "flags" : | 1737 | case "flags" : |
1749 | result.Flags = UInt32.Parse(ic.xml.Value); | 1738 | result.Flags = UInt32.Parse(ic.xml.Value); |
1750 | break; | 1739 | break; |
1751 | case "creationdate" : | 1740 | case "creationdate" : |
1752 | result.CreationDate = Int32.Parse(ic.xml.Value); | 1741 | result.CreationDate = Int32.Parse(ic.xml.Value); |
1753 | break; | 1742 | break; |
1754 | case "saletype" : | 1743 | case "saletype" : |
1755 | result.SaleType = Byte.Parse(ic.xml.Value); | 1744 | result.SaleType = Byte.Parse(ic.xml.Value); |
1756 | break; | 1745 | break; |
1757 | case "saleprice" : | 1746 | case "saleprice" : |
1758 | result.SalePrice = Int32.Parse(ic.xml.Value); | 1747 | result.SalePrice = Int32.Parse(ic.xml.Value); |
1759 | break; | 1748 | break; |
1760 | 1749 | ||
1761 | default : | 1750 | default : |
1762 | Rest.Log.DebugFormat("{0} Item: Unrecognized attribute: {1}:{2}", | 1751 | Rest.Log.DebugFormat("{0} Item: Unrecognized attribute: {1}:{2}", |
1763 | MsgId, ic.xml.Name, ic.xml.Value); | 1752 | MsgId, ic.xml.Name, ic.xml.Value); |
1764 | ic.Fail(Rest.HttpStatusCodeBadRequest, String.Format("unrecognized attribute", | 1753 | ic.Fail(Rest.HttpStatusCodeBadRequest, String.Format("unrecognized attribute", |
1765 | ic.xml.Name)); | 1754 | ic.xml.Name)); |
1766 | break; | 1755 | break; |
1767 | } | 1756 | } |
1768 | } | 1757 | } |
1769 | } | 1758 | } |
@@ -1793,7 +1782,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
1793 | /// An asset, if created is stored in the | 1782 | /// An asset, if created is stored in the |
1794 | /// XmlInventoryCollection | 1783 | /// XmlInventoryCollection |
1795 | /// </summary> | 1784 | /// </summary> |
1796 | |||
1797 | private void CollectAsset(XmlInventoryCollection ic) | 1785 | private void CollectAsset(XmlInventoryCollection ic) |
1798 | { | 1786 | { |
1799 | Rest.Log.DebugFormat("{0} Interpret asset element", MsgId); | 1787 | Rest.Log.DebugFormat("{0} Interpret asset element", MsgId); |
@@ -1885,7 +1873,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
1885 | { | 1873 | { |
1886 | string b64string = null; | 1874 | string b64string = null; |
1887 | 1875 | ||
1888 | // Generate a UUID of none were given, and generally none should | 1876 | // Generate a UUID if none were given, and generally none should |
1889 | // be. Ever. | 1877 | // be. Ever. |
1890 | 1878 | ||
1891 | if (uuid == UUID.Zero) | 1879 | if (uuid == UUID.Zero) |
@@ -1927,7 +1915,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
1927 | } | 1915 | } |
1928 | 1916 | ||
1929 | ic.Push(asset); | 1917 | ic.Push(asset); |
1930 | |||
1931 | } | 1918 | } |
1932 | 1919 | ||
1933 | /// <summary> | 1920 | /// <summary> |
@@ -1935,7 +1922,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory | |||
1935 | /// This overrides the default permissions set when the | 1922 | /// This overrides the default permissions set when the |
1936 | /// XmlInventoryCollection object was created. | 1923 | /// XmlInventoryCollection object was created. |
1937 | /// </summary> | 1924 | /// </summary> |
1938 | |||
1939 | private void CollectPermissions(XmlInventoryCollection ic) | 1925 | private void CollectPermissions(XmlInventoryCollection ic) |
1940 | { | 1926 | { |
1941 | if (ic.xml.HasAttributes) | 1927 | if (ic.xml.HasAttributes) |